﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;

namespace EasyTrader.Option
{
    using PriceSignalList = List<EasyTrader.Signal.PriceSignal>;
    public class StateWatcher
    {
#region Common Functions
        public void SetSigInfo(int a_CurIndex, int a_SigType, double a_CompVal, ref EasyTrader.Signal.PriceSignal a_CurSignal)
        {
            int signalTime = 0;
            if (GlobalVar.OperationMode == GlobalVar.OperationModeSimul)
                signalTime = GlobalVar.DayIndexToTimeEx(a_CurIndex);
            else
            {
                signalTime = GlobalVar.TimeToIntEx();
            }
            a_CurSignal.Time = signalTime;
            a_CurSignal.X = a_CurIndex;
            a_CurSignal.OptSigCode = m_OpCode;
            a_CurSignal.OptSigTime = GlobalVar.DayIndexToTime(a_CurIndex);
            a_CurSignal.OptSigType = a_SigType;
            a_CurSignal.OptSigVal = a_CompVal;
        }
        public void WriteSignalLog(int a_CurIndex, EasyTrader.Signal.PriceSignal a_Signal, string a_HeaderMsg, double a_CurVal, EasyTrader.Option.CompVal a_CompVal)
        {
            if (a_Signal == null)
                return;

            string logMsg = a_HeaderMsg;
            logMsg += ", 인덱스 :" + a_CurIndex.ToString();
            logMsg += ", 현재시간 : " + GlobalVar.GetCurTime();
            logMsg += ", 현재 가격 : " + a_CurVal.ToString("F2");
            logMsg += ", 옵션 가격 : " + a_Signal.OptSigVal.ToString("F2");
            logMsg += ", 옵션 코드 : " + a_Signal.OptSigCode;
            logMsg += ", 옵션 시간 : " + a_Signal.OptSigTime.ToString();
            logMsg += ", 옵션 신호종류 : ";
            if (a_Signal.OptSigType == GlobalVar.OpSignalNone)
            {
                logMsg += "신호없음";
            }
            else if (a_Signal.OptSigType == GlobalVar.OpSignalBreakDownEnter)
            {
                logMsg += "붕괴";
            }
            else if (a_Signal.OptSigType == GlobalVar.OpSignalBreakUpEnter)
            {
                logMsg += "돌파";
            }
            else if (a_Signal.OptSigType == GlobalVar.OpSignalDownLiq)
            {
                logMsg += "내려가면서 청산";
            }
            else if (a_Signal.OptSigType == GlobalVar.OpSignalUpLiq)
            {
                logMsg += "올라오면서 청산";
            }
            else
            {
                logMsg += "알수없음";
            }

            GlobalVar.WriteLog(logMsg);
        }
#endregion
#region  Member Variables
        private EasyTrader.Signal.PriceSignal m_CurSignal = new EasyTrader.Signal.PriceSignal();

        private double[] OpMainPrice = new double[6] { 1.20, 2.50, 3.5, 4.85, 5.2, 6.85 };
        //private int m_Signal = GlobalVar.OpSignalNone;
        private EasyTrader.Option.OptSignal m_Signal = new EasyTrader.Option.OptSignal();
        public EasyTrader.Option.OptSignal Signal
        {
            get { return m_Signal; }
            set { m_Signal = value; }
        }

        private EasyTrader.Option.OptSignal m_OverSignal = new EasyTrader.Option.OptSignal();
        public EasyTrader.Option.OptSignal OverSignal
        {
            get { return m_OverSignal; }
            set { m_OverSignal = value; }
        }
        private double m_CounterMonthHigh = 0.0;
        public double CounterMonthHigh
        {
            get { return m_CounterMonthHigh; }
            set { m_CounterMonthHigh = value; }
        }

#endregion

#region MainPriceFunctions
        public void FindOHLSignal(int a_CurIndex)
        {
            FindOHLSignalMainPrice(a_CurIndex);
            FindOHLSignalMonthHigh(a_CurIndex);
            FindOHLSignalGeneral(a_CurIndex);
        }

        public void FindBreakHighLow(int a_CurIndex)
        {
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            GetOHLC(m_Table, 0, a_CurIndex, ref open, ref high, ref low, ref close);
            double highLimit = 0.0;
            double lowLimit = 0.0;
            if (open > 3.0)
            {
                highLimit = open + 0.01;
                lowLimit = open - 0.01;
            }
            else
            {
                highLimit = open + 0.05;
                lowLimit = open - 0.05;
            }

            if (close > highLimit)
            {
                m_OverSignal.SigType = GlobalVar.OpSignalOverHigh;
                m_OverSignal.Code = m_OpCode;
                m_OverSignal.OpenVal = open;
            }
            else if (close < lowLimit)
            {
                m_OverSignal.SigType = GlobalVar.OpSignalUnderLow;
                m_OverSignal.Code = m_OpCode;
                m_OverSignal.OpenVal = open;
            }
        }

        public void FindOHLSignalMainPrice(int a_CurIndex)
        {
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            GetOHLC(m_Table, 0, a_CurIndex, ref open, ref high, ref low, ref close);
            if (high != low)
            {
                for (int i = 0; i < OpMainPrice.Length; i++)
                {
                    double price = OpMainPrice[i];
                    if (price == open)
                    {
                        if (open == high)
                        {
                            m_Signal.SigType = GlobalVar.OpSignalHighBeginMP;
                            m_Signal.Code = OpCode;
                            m_Signal.MainPrice = price;
                            break;
                        }
                        else if (open == low)
                        {
                            m_Signal.SigType = GlobalVar.OpSignalLowBeginMP;
                            m_Signal.Code = OpCode;
                            m_Signal.MainPrice = price;
                            break;
                        }
                    }
                }
            }
        }

        
        public void FindOHLSignalMonthHigh(int a_CurIndex)
        {
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            GetOHLC(m_Table, 0, a_CurIndex, ref open, ref high, ref low, ref close);
            if (high != low)
            {
                if (m_CounterMonthHigh == open)
                {
                    if (open == high)
                    {
                        m_Signal.SigType = GlobalVar.OpSignalHighBeginMH;
                        m_Signal.Code = OpCode;
                        m_Signal.MonthHigh = m_CounterMonthHigh;
                    }
                    else if (open == low)
                    {
                        m_Signal.SigType = GlobalVar.OpSignalLowBeginMH;
                        m_Signal.Code = OpCode;
                        m_Signal.MonthHigh = m_CounterMonthHigh;
                    }
                }
            }
        }

        public void FindOHLSignalGeneral(int a_CurIndex)
        {
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            GetOHLC(m_Table, 0, a_CurIndex, ref open, ref high, ref low, ref close);
            if (high != low)
            {
                double highLimit = 0.0;
                double lowLimit = 0.0;
                if (open > 3.0)
                {
                    highLimit = open + 0.01;
                    lowLimit = open - 0.01;
                }
                else
                {
                    highLimit = open + 0.05;
                    lowLimit = open - 0.05;
                }
                
                if (open == high)
                {
                    if (close < lowLimit)
                    {
                        m_Signal.SigType = GlobalVar.OpSignalHighBeginGP;
                        m_Signal.Code = OpCode;
                        m_Signal.OpenVal = open;
                        Console.WriteLine("hlSignal-> OpSignalHighBeginGP code :: " + OpCode + "open ::" + open.ToString("F2"));
                    }
                }
                else if (open == low)
                {
                    if (close > highLimit)
                    {
                        m_Signal.SigType = GlobalVar.OpSignalLowBeginGP;
                        m_Signal.Code = OpCode;
                        m_Signal.OpenVal = open;
                        Console.WriteLine("hlSignal-> OpSignalLowBeginGP code :: " + OpCode + "open ::" + open.ToString("F2"));
                    }
                }
                else
                {
                    if (high <= highLimit && high >= open)
                    {
                        if (close < lowLimit)
                        {
                            m_Signal.SigType = GlobalVar.OpSignalHighBeginGP;
                            m_Signal.Code = OpCode;
                            m_Signal.OpenVal = open;
                            Console.WriteLine("hlSignal-> OpSignalHighBeginGP code :: " + OpCode + "open ::" + open.ToString("F2"));
                        }
                    }
                    else if (low <= open && low >= lowLimit)
                    {
                        if (close > highLimit)
                        {
                            m_Signal.SigType = GlobalVar.OpSignalLowBeginGP;
                            m_Signal.Code = OpCode;
                            m_Signal.OpenVal = open;
                            Console.WriteLine("hlSignal-> OpSignalLowBeginGP code :: " + OpCode + "open ::" + open.ToString("F2"));
                        }
                    }
                }
            }
        }
#endregion
        private int OldRange = GlobalVar.NoneRange;
        private int OldUpDown = GlobalVar.NoneRange;

        private StateWatcherList m_Parent = null;
        public EasyTrader.Option.StateWatcherList Parent
        {
            get { return m_Parent; }
            set { m_Parent = value; }
        }
        private PriceSignalList m_BreakDownSignalList = new PriceSignalList();

        private PriceSignalList m_BreakUpSignalList = new PriceSignalList();
        
        private int m_BreakDownCount = 0;
        public int BreakDownCount
        {
            get { return m_BreakDownCount; }
            set { m_BreakDownCount = value; }
        }
        private int m_BreakUpCount = 0;
        public int BreakUpCount
        {
            get { return m_BreakUpCount; }
            set { m_BreakUpCount = value; }
        }

        private EasyTrader.Signal.PriceSignal GetLastBreakDownSignal()
        {
            int count = m_BreakDownSignalList.Count;
            if (count == 0)
                return null;

            return m_BreakDownSignalList[count - 1];
        }

        private EasyTrader.Signal.PriceSignal GetLastBreakUpSignal()
        {
            int count = m_BreakUpSignalList.Count;
            if (count == 0)
                return null;

            return m_BreakUpSignalList[count - 1];
        }

        private EasyTrader.Signal.PriceSignal GetRecentLiqDownSignal()
        {
            return null;
        }

        public EasyTrader.Signal.PriceSignal FindSignal(int a_CurIndex, int a_Mode)
        {
            PriceSignalList signalList = null;
            // 제일 먼저 청산 신호를 파악한다.
            if (a_Mode == GlobalVar.OpSignalModeBreakDown)
            {
                signalList = m_BreakDownSignalList;
            }
            else
            {
                signalList = m_BreakUpSignalList;
            }

            // 제일 먼저 청산 신호가 있는지 확인한다.
            EasyTrader.Signal.PriceSignal activeSignal = FindLiqSignal(a_CurIndex, a_Mode);
            if (activeSignal != null)
            {
                activeSignal = CheckAddSignal(signalList, activeSignal);
                if (activeSignal != null)
                {
                    return activeSignal;
                }
            }

            // 붕괴/돌파로 인한 신호가 있는지 확인한다.
            activeSignal = FindUpDownSignal(a_CurIndex, a_Mode);
            if (activeSignal != null)
            {
                activeSignal = CheckAddSignal(signalList, activeSignal);
                if (activeSignal != null)
                {
                    return activeSignal;
                }
            }

            // 지지와 저항으로 인한 신호가 있는지 확인한다.
            activeSignal = FindResSupSignal(a_CurIndex, a_Mode);
            if (activeSignal != null)
            {
                activeSignal = CheckAddSignal(signalList, activeSignal);
                if (activeSignal != null)
                {
                    return activeSignal;
                }
            }
            return null;
        }

        public EasyTrader.Signal.PriceSignal CheckAddSignal(PriceSignalList a_SignalList, EasyTrader.Signal.PriceSignal a_Signal)
        {
            if (a_Signal == null || a_SignalList == null)
                return null;
            int count = a_SignalList.Count;

            EasyTrader.Signal.PriceSignal newSignal = null;
            if (count <= 0)
            {
                newSignal = a_Signal.Clone();
                a_SignalList.Add(newSignal);
                return newSignal;
            }
            else
            {
                EasyTrader.Signal.PriceSignal prevSignal = a_SignalList[count - 1];
                // 이전 신호와 신호 발생시간이 같지 않아야 한다.
                if (prevSignal.OptSigTime != a_Signal.OptSigTime)
                {
                    // 신호 타입이 다르면 그대로 받아 들인다.
                    if (prevSignal.OptSigType != a_Signal.OptSigType)
                    {
                        newSignal = a_Signal.Clone();
                        a_SignalList.Add(newSignal);
                        return newSignal;
                    }
                    else
                    {
                        // 신호 타입이 같을 경우 비교 값이 다를 때만 받아 들인다.
                        if (prevSignal.OptSigVal != a_Signal.OptSigVal)
                        {
                            newSignal = a_Signal.Clone();
                            a_SignalList.Add(newSignal);
                            return newSignal;
                        }
                    }
                }
            }

            return null;
        }

        public EasyTrader.Signal.PriceSignal CheckAddSignalOld(PriceSignalList a_SignalList, EasyTrader.Signal.PriceSignal a_Signal)
        {
            if (a_Signal == null || a_SignalList == null)
                return null;
            int count = a_SignalList.Count;

            EasyTrader.Signal.PriceSignal newSignal = null;
            if (count <= 0)
            {
                newSignal = a_Signal.Clone();
                a_SignalList.Add(newSignal);
                return newSignal;
            }
            else
            {
                EasyTrader.Signal.PriceSignal prevSignal = a_SignalList[count - 1];
                if (a_Signal.OptSigType == GlobalVar.OpSignalDownLiq || a_Signal.OptSigType == GlobalVar.LiqUp)
                {
                    // 신호 타입이 다르면 그대로 받아 들인다.
                    if (prevSignal.OptSigType != a_Signal.OptSigType)
                    {
                        newSignal = a_Signal.Clone();
                        a_SignalList.Add(newSignal);
                        return newSignal;
                    }
                    else
                    {
                        // 신호 타입이 같을 경우 비교 값이 다를 때만 받아 들인다.
                        if (prevSignal.OptSigVal != a_Signal.OptSigVal)
                        {
                            newSignal = a_Signal.Clone();
                            a_SignalList.Add(newSignal);
                            return newSignal;
                        }
                    }
                }
                else
                {
                    newSignal = a_Signal.Clone();
                    a_SignalList.Add(newSignal);
                    return newSignal;
                }
            }

            return null;
        }

        // 이 함수는 모드에 따라 필요할 때에 2번 부를 수 있다.
        // 손절은 현재 같은 가격에서만 일어날 수 있게 되어 있다. 차후 손절은 같은 가격이 아니라 일정한 가격 범위에서 일어나게 할 수도 있다
        public EasyTrader.Signal.PriceSignal FindUpDownSignal(int a_CurIndex, int a_Mode)
        {
            // 붕괴 우선 모드시 - 높은 가격부터 조사를 한다.
            if (a_Mode == GlobalVar.OpSignalModeBreakDown)
            {
                EasyTrader.Signal.PriceSignal lastBreakDownSig = GetLastBreakDownSignal();
                // 저마기목월 순서로 되어 있다. 
                for (int i = m_ComValList.Count - 1; i >= 0; i--) 
                {
                    if (IsEnable(i) == true)
                    {
                        EasyTrader.Option.CompVal compVal = m_ComValList[i];
                        double close = 0.0;
                        int curSig = FindUpDownSignal(compVal, m_Table, a_CurIndex, out close);
                        if (curSig == GlobalVar.BreakDown)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalBreakDownEnter, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "붕괴 발생", close, compVal);
                            return m_CurSignal;
                        }
                        else if (curSig == GlobalVar.BreakUp)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalBreakUpLiq, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "돌파 발생", close, compVal);
                            return m_CurSignal;
                        }
                    }
                }
            }
            else if (a_Mode == GlobalVar.OpSignalModeBreakUp) // 돌파 우선 모드시 - 낮은 가격부터 조사를 한다.
            {
                EasyTrader.Signal.PriceSignal lastBreakUpSig = GetLastBreakUpSignal();
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    if (IsEnable(i) == true)
                    {
                        EasyTrader.Option.CompVal compVal = m_ComValList[i];
                        double close = 0.0;
                        int curSig = FindUpDownSignal(compVal, m_Table, a_CurIndex, out close);
                        if (curSig == GlobalVar.BreakUp)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalBreakUpEnter, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "돌파 발생", close, compVal);
                            return m_CurSignal;
                        }
                        else if (curSig == GlobalVar.BreakDown)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalBreakDownLiq, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "붕괴 발생", close, compVal);
                            return m_CurSignal;
                        }
                    }
                }
            }
            return null;
        }

        private bool IsEnable(int a_ValType)
        {
            if (a_ValType == 0)
            {
                if (GlobalVar.OptValMonthLow == true)
                    return true;
                else
                    return false;
            }
            else if (a_ValType == 1)
            {
                if (GlobalVar.OptValLowTarget == true)
                    return true;
                else
                    return false;
            }
            else if (a_ValType == 2)
            {
                if (GlobalVar.OptValBase == true)
                    return true;
                else
                    return false;
            }
            else if (a_ValType == 3)
            {
                if (GlobalVar.OptValHighTarget == true)
                    return true;
                else
                    return false;
            }
            else if (a_ValType == 4)
            {
                if (GlobalVar.OptValMonthHigh == true)
                    return true;
                else
                    return false;
            }
            else
                return false;
        }

        // 이 함수는 모드에 따라 필요할 때에 2번 부를 수 있다.
        // 청산은 이전 신호와 같은 가격대에서는 절대로 일어날 수가 없다.
        // 붕괴모드에서는 신호 발생 가격보다 낮아야 하고 돌파 모드에서는 높아야 한다.
        // 현재 청산은 모든 시스템에 적용되어야 하므로 조건없이 내주는 것으로 한다.
        // 단 단독 시스템일 때는 청산할 것이 없으면 신호를 내지 않는다.
        public EasyTrader.Signal.PriceSignal FindLiqSignal(int a_CurIndex, int a_Mode)
        {
            // 붕괴 우선 모드시 - 낮은 가격부터 조사를 한다. - 청산은 그 가격에 도달을 보기 때문에 먼 가격부터 조사를 해온다.
            if (a_Mode == GlobalVar.OpSignalModeBreakDown)
            {
                //EasyTrader.Signal.PriceSignal lastBreakDownSig = m_BreakDownSignalList[m_BreakDownSignalList.Count - 1];
                // 저마기목월 순서로 되어 있다. 
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    if (IsEnable(i) == true)
                    {
                        EasyTrader.Option.CompVal compVal = m_ComValList[i];
                        double close = 0.0;
                        int curSig = FindLiqSignal(compVal, m_Table, a_CurIndex, out close);
                        if (curSig == GlobalVar.LiqDown)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalDownLiq, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "하향하면서 청산", close, compVal);
                            return m_CurSignal;
                        }
                    }
                }
            }
            else if (a_Mode == GlobalVar.OpSignalModeBreakUp) // 돌파 우선 모드시 - 높은 가격부터 조사를 한다. - 먼가격부터 조사를 해서 도달 여부를 보기 때문이다.
            {
                //EasyTrader.Signal.PriceSignal lastBreakUpSig = m_BreakUpSignalList[m_BreakUpSignalList.Count - 1];
                for (int i = m_ComValList.Count - 1; i >= 0; i--)
                {
                    if (IsEnable(i) == true)
                    {
                        EasyTrader.Option.CompVal compVal = m_ComValList[i];
                        double close = 0.0;
                        int curSig = FindLiqSignal(compVal, m_Table, a_CurIndex, out close);
                        if (curSig == GlobalVar.LiqUp)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalUpLiq, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "상향하면서 청산", close, compVal);
                            return m_CurSignal;
                        }
                    }
                }
            }
            return null;
        }

        public EasyTrader.Signal.PriceSignal FindResSupSignal(int a_CurIndex)
        {
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                EasyTrader.Option.CompVal compVal = m_ComValList[i];
                double close = 0.0;
                int curSig = FindFullResSupSignal(compVal, m_Table, a_CurIndex, out close);
                compVal.DeltaY = close - compVal.Val;
                if (curSig == GlobalVar.Resist)
                {
                    SetSigInfo(a_CurIndex, GlobalVar.OpSignalResist, compVal.Val, ref m_CurSignal);
                    WriteSignalLog(a_CurIndex, m_CurSignal, "저항 발생", close, compVal);
                    return m_CurSignal;
                }
                else if (curSig == GlobalVar.Support)
                {
                    SetSigInfo(a_CurIndex, GlobalVar.OpSignalSupport, compVal.Val, ref m_CurSignal);
                    WriteSignalLog(a_CurIndex, m_CurSignal, "지지 발생", close, compVal);
                    return m_CurSignal;
                }
            }

            return null;
        }

        public EasyTrader.Signal.PriceSignal FindBendSignal(int a_CurIndex)
        {
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                EasyTrader.Option.CompVal compVal = m_ComValList[i];
                double close = 0.0;
                int curSig = FindBendSignal(compVal, m_Table, a_CurIndex, out close);
                compVal.DeltaY = close - compVal.Val;
                if (curSig == GlobalVar.SignalBuy)
                {
                    SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                    WriteSignalLog(a_CurIndex, m_CurSignal, "저점꺾기 발생", close, compVal);
                    return m_CurSignal;
                }
                else if (curSig == GlobalVar.SignalSell)
                {
                    SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                    WriteSignalLog(a_CurIndex, m_CurSignal, "고점꺾기 발생", close, compVal);
                    return m_CurSignal;
                }
            }

            return null;
        }

        public EasyTrader.Signal.PriceSignal FindBendSignal(int a_CurIndex, int a_UpDown)
        {
            double close = 0.0;
            double high = 0.0;
            double low = 0.0;
            double open = 0.0;
            int highIndex = 0;
            int lowIndex = 0;
            int recentIndex = 0;
            double min = 0.0, max = 0.0;
            recentIndex = GlobalVar.FindHighLowIndex(m_Table, a_CurIndex - GlobalVar.BackRefRange, a_CurIndex, ref highIndex, ref lowIndex, ref min, ref max, ref open, ref close, ref low, ref high);
            int minIndex = Math.Min(highIndex, lowIndex);

            EasyTrader.Option.CompVal nextVal = null;
            // 상승시 낮은 가격부터 조사한다.
            if (a_UpDown == GlobalVar.PriceUp)
            {
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal compVal = m_ComValList[i];
                    if (i + 1 < m_ComValList.Count)
                    {
                        nextVal = m_ComValList[i + 1];
                        if (Math.Abs(nextVal.Val - compVal.Val) <= 0.1)
                            continue;
                    }

                    if (recentIndex >= 0)
                    {
                        //string hrange = (compVal.Val + 0.02).ToString("F2");
                        //double hrangeVal = Convert.ToDouble(hrange);
                        //string lrange = (compVal.Val - 0.02).ToString("F2");
                        //double lrangeVal = Convert.ToDouble(lrange);
                        if (max == compVal.Val) // 가격 일치
                        {
                            string range = (max - GlobalVar.ErrorRange).ToString("F2");
                            double rangeVal = Convert.ToDouble(range);
                            if (highIndex >= lowIndex && close < rangeVal)
                            {
                                SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                                WriteSignalLog(a_CurIndex, m_CurSignal, "가격 일치 후 고점꺾기 발생", close, compVal);
                                return m_CurSignal;
                            }
                        }
                        else
                        {
                            string hrange = (compVal.Val + GlobalVar.OptErrorRange).ToString("F2");
                            double hrangeVal = Convert.ToDouble(hrange);
                            string lrange = (compVal.Val - GlobalVar.OptErrorRange).ToString("F2");
                            double lrangeVal = Convert.ToDouble(lrange);
                            if (max >= lrangeVal && max <= hrangeVal)
                            {
                                // 오차 범위 안에 있을 때
                                if (highIndex >= lowIndex)
                                {
                                    if (max > compVal.Val) // 최대 값이 값보다 클 때
                                    {
                                        if (close < compVal.Val)
                                        {
                                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                                            WriteSignalLog(a_CurIndex, m_CurSignal, "오차범위 내에서 돌파후 붕괴로 고점꺾기 발생", close, compVal);
                                            return m_CurSignal;
                                        }
                                    }
                                    else // 최대 값이 값보다 작거나 같을 때
                                    {
                                        string range = (max - GlobalVar.FutErrorRange).ToString("F2");
                                        double rangeVal = Convert.ToDouble(range);
                                        if (minIndex <= 1 && minIndex == highIndex)
                                        {
                                            if (close < rangeVal)
                                            {
                                                SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                                                WriteSignalLog(a_CurIndex, m_CurSignal, "최초로 오차범위 내에서 고점꺾기 발생", close, compVal);
                                                return m_CurSignal;
                                            }
                                        }
                                        else
                                        {
                                            int inRangeCount = GlobalVar.InRangeCount(m_Table, a_CurIndex - GlobalVar.BackRefRange, a_CurIndex, max, GlobalVar.HighTarget);
                                            if (inRangeCount >= 2 && close <= rangeVal)
                                            {
                                                SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                                                WriteSignalLog(a_CurIndex, m_CurSignal, "오차범위 내에서 값에 못 미쳐 고점꺾기 발생", close, compVal);
                                                return m_CurSignal;
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // 오차 범위 밖에 있을 때
                                int upDown = GlobalVar.BreakNone;
                                upDown = GlobalVar.FindBreakUpDown(m_Table, a_CurIndex - GlobalVar.BackRefRange, a_CurIndex, compVal.Val);
                                if (upDown == GlobalVar.BreakDown)
                                {
                                    SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                                    WriteSignalLog(a_CurIndex, m_CurSignal, "오차범위 밖에서 가격 붕괴로 고점꺾기 발생", close, compVal);
                                    return m_CurSignal;
                                }
                            }
                        }
                    }
                }
            }
            else if (a_UpDown == GlobalVar.PriceDown) // 하락시 높은 가격부터 조사한다.
            {
                for (int i = m_ComValList.Count - 1; i >= 0; i--)
                {
                    
                    EasyTrader.Option.CompVal compVal = m_ComValList[i];
                    if (compVal.BreakCode == "301H9252")
                    {
                        int k = 0;
                        k = k + 1;
                    }
                    if (i - 1 >= 0)
                    {
                        nextVal = m_ComValList[i - 1];
                        if (Math.Abs(nextVal.Val - compVal.Val) <= 0.1)
                            continue;
                    }
                    if (recentIndex >= 0)
                    {
                        //string hrange = (compVal.Val + 0.02).ToString("F2");
                        //double hrangeVal = Convert.ToDouble(hrange);
                        //string lrange = (compVal.Val - 0.02).ToString("F2");
                        //double lrangeVal = Convert.ToDouble(lrange);
                        if (min == compVal.Val) // 가격 일치
                        {
                            string range = (min + GlobalVar.ErrorRange).ToString("F2");
                            double rangeVal = Convert.ToDouble(range);
                            if (lowIndex >= highIndex && close > rangeVal)
                            {
                                SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                                WriteSignalLog(a_CurIndex, m_CurSignal, "가격 일치 후 저점꺾기 발생", close, compVal);
                                return m_CurSignal;
                            }
                        }
                        else
                        {
                            string hrange = (compVal.Val + GlobalVar.OptErrorRange).ToString("F2");
                            double hrangeVal = Convert.ToDouble(hrange);
                            string lrange = (compVal.Val - GlobalVar.OptErrorRange).ToString("F2");
                            double lrangeVal = Convert.ToDouble(lrange);
                            if (min >= lrangeVal && min <= hrangeVal)
                            {
                                // 오차 범위 안에 있을 때
                                if (lowIndex >= highIndex)
                                {
                                    if (min < compVal.Val) // 최소값이 비교값보다 작을 때
                                    {
                                        if (close > compVal.Val)
                                        {
                                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                                            WriteSignalLog(a_CurIndex, m_CurSignal, "오차 범위 내에서 붕괴후 돌파로 저점꺾기 발생", close, compVal);
                                            return m_CurSignal;
                                        }
                                    }
                                    else // 최소값이 비교값보다 크거나 같을 때
                                    {
                                        string range = (min + GlobalVar.FutErrorRange).ToString("F2");
                                        double rangeVal = Convert.ToDouble(range);
                                        if (minIndex <= 1 && minIndex == lowIndex)
                                        {
                                            if (close >= rangeVal)
                                            {
                                                SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                                                WriteSignalLog(a_CurIndex, m_CurSignal, "최초로 오차범위 내에서 시작하여 저점꺾기 발생", close, compVal);
                                                return m_CurSignal;
                                            }
                                        }
                                        else
                                        {
                                            int inRangeCount = GlobalVar.InRangeCount(m_Table, a_CurIndex - GlobalVar.BackRefRange, a_CurIndex, min, GlobalVar.LowTarget);
                                            if (inRangeCount >= 2 && close >= rangeVal)
                                            {
                                                SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                                                WriteSignalLog(a_CurIndex, m_CurSignal, "오차범위 내에서 값에 못 미쳐 저점꺾기 발생", close, compVal);
                                                return m_CurSignal;
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                // 오차 범위 밖에 있을 때
                                int upDown = GlobalVar.BreakNone;
                                upDown = GlobalVar.FindBreakUpDown(m_Table, a_CurIndex - GlobalVar.BackRefRange, a_CurIndex, compVal.Val);
                                if (upDown == GlobalVar.BreakUp)
                                {
                                    SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                                    WriteSignalLog(a_CurIndex, m_CurSignal, "오차범위 밖에서 가격 돌파로 저점꺾기 발생", close, compVal);
                                    return m_CurSignal;
                                }
                            }
                        }
                    }
                }
            }

            return null;
        }


        public EasyTrader.Signal.PriceSignal FindNearOpVal(int a_CurIndex, int a_UpDown, ref EasyTrader.Option.CompVal a_NearVal)
        {
            double close = 0.0;
            double high = 0.0;
            double low = 0.0;
            double open = 0.0;
            
            GlobalVar.GetOHLC(m_Table, a_CurIndex, out open, out high, out low, out close);
            EasyTrader.Option.CompVal nextVal = null;
            // 상승시 낮은 가격부터 조사한다.
            if (a_UpDown == GlobalVar.PriceUp)
            {
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal compVal = m_ComValList[i];
                    if (i + 1 < m_ComValList.Count)
                    {
                        nextVal = m_ComValList[i + 1];
                        if (Math.Abs(nextVal.Val - compVal.Val) <= 0.1)
                            continue;
                    }
                    double deltaY = Math.Abs(compVal.Val - close);
                    if (deltaY < Math.Abs(a_NearVal.DeltaY))
                    {
                        a_NearVal.BreakCode = compVal.BreakCode;
                        a_NearVal.Val = compVal.Val;
                        a_NearVal.Type = compVal.Type;
                        a_NearVal.Index = a_CurIndex;
                        a_NearVal.DeltaY = close - compVal.Val;
                        a_NearVal.CurVal = close;
                    }
                }
            }
            else if (a_UpDown == GlobalVar.PriceDown) // 하락시 높은 가격부터 조사한다.
            {
                for (int i = m_ComValList.Count - 1; i >= 0; i--)
                {

                    EasyTrader.Option.CompVal compVal = m_ComValList[i];
                    if (i - 1 >= 0)
                    {
                        nextVal = m_ComValList[i - 1];
                        if (Math.Abs(nextVal.Val - compVal.Val) <= 0.1)
                            continue;
                    }
                    double deltaY = Math.Abs(compVal.Val - close);
                    if (deltaY < Math.Abs(a_NearVal.DeltaY))
                    {
                        a_NearVal.BreakCode = compVal.BreakCode;
                        a_NearVal.Val = compVal.Val;
                        a_NearVal.Type = compVal.Type;
                        a_NearVal.Index = a_CurIndex;
                        a_NearVal.DeltaY = close - compVal.Val;
                        a_NearVal.CurVal = close;
                    }
                }
            }

            return null;
        }


        public EasyTrader.Signal.PriceSignal FindBendSignalOld2(int a_CurIndex, int a_UpDown)
        {
            EasyTrader.Option.CompVal nextVal = null;
            // 상승시 낮은 가격부터 조사한다.
            if (a_UpDown == GlobalVar.PriceUp)
            {
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal compVal = m_ComValList[i];
                    if (i + 1 < m_ComValList.Count)
                    {
                        nextVal = m_ComValList[i + 1];
                        if (Math.Abs(nextVal.Val - compVal.Val) <= 0.1)
                            continue;
                    }
                    double close = 0.0;
                    int curSig = FindBendSignal(compVal, m_Table, a_CurIndex, out close);
                    compVal.DeltaY = close - compVal.Val;
                    if (curSig == GlobalVar.SignalBuy)
                    {
                        SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                        WriteSignalLog(a_CurIndex, m_CurSignal, "저점꺾기 발생", close, compVal);
                        return m_CurSignal;
                    }
                    else if (curSig == GlobalVar.SignalSell)
                    {
                        SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                        WriteSignalLog(a_CurIndex, m_CurSignal, "고점꺾기 발생", close, compVal);
                        return m_CurSignal;
                    }
                }
            }
            else if (a_UpDown == GlobalVar.PriceDown) // 하락시 높은 가격부터 조사한다.
            {
                for (int i = m_ComValList.Count - 1; i >= 0; i--)
                {
                    EasyTrader.Option.CompVal compVal = m_ComValList[i];
                    if (i - 1 >= 0)
                    {
                        nextVal = m_ComValList[i - 1];
                        if (Math.Abs(nextVal.Val - compVal.Val) <= 0.1)
                            continue;
                    }
                    double close = 0.0;
                    int curSig = FindBendSignal(compVal, m_Table, a_CurIndex, out close);
                    compVal.DeltaY = close - compVal.Val;
                    if (curSig == GlobalVar.SignalBuy)
                    {
                        SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendLow, compVal.Val, ref m_CurSignal);
                        WriteSignalLog(a_CurIndex, m_CurSignal, "저점꺾기 발생", close, compVal);
                        return m_CurSignal;
                    }
                    else if (curSig == GlobalVar.SignalSell)
                    {
                        SetSigInfo(a_CurIndex, GlobalVar.OpSignalBendHigh, compVal.Val, ref m_CurSignal);
                        WriteSignalLog(a_CurIndex, m_CurSignal, "고점꺾기 발생", close, compVal);
                        return m_CurSignal;
                    }
                }
            }

            return null;
        }

        public EasyTrader.Signal.PriceSignal FindResSupSignal(int a_CurIndex, int a_Mode)
        {
            // 붕괴 우선 모드시 - 낮은 가격부터 조사를 한다. - 청산은 그 가격에 도달을 보기 때문에 먼 가격부터 조사를 해온다.
            if (a_Mode == GlobalVar.OpSignalModeBreakDown)
            {
                EasyTrader.Signal.PriceSignal lastBreakDownSig = GetLastBreakDownSignal();
                // 저마기목월 순서로 되어 있다. 
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    if (IsEnable(i) == true)
                    {
                        EasyTrader.Option.CompVal compVal = m_ComValList[i];
                        double close = 0.0;
                        int curSig = FindResSupSignal(compVal, m_Table, a_CurIndex, out close);
                        if (curSig == GlobalVar.Resist)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalResist, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "저항 발생", close, compVal);
                            return m_CurSignal;
                        }
                        else if (curSig == GlobalVar.Support)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalSupport, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "지지 발생", close, compVal);
                            return m_CurSignal;
                        }
                    }
                }
            }
            else if (a_Mode == GlobalVar.OpSignalModeBreakUp) // 돌파 우선 모드시 - 높은 가격부터 조사를 한다. - 먼가격부터 조사를 해서 도달 여부를 보기 때문이다.
            {
                EasyTrader.Signal.PriceSignal lastBreakUpSig = GetLastBreakUpSignal();
                for (int i = m_ComValList.Count - 1; i >= 0; i--)
                {
                    if (IsEnable(i) == true)
                    {
                        EasyTrader.Option.CompVal compVal = m_ComValList[i];
                        double close = 0.0;
                        int curSig = FindResSupSignal(compVal, m_Table, a_CurIndex, out close);
                        if (curSig == GlobalVar.Support)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalSupport, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "지지 발생", close, compVal);
                            return m_CurSignal;
                        }
                        else if (curSig == GlobalVar.Resist)
                        {
                            SetSigInfo(a_CurIndex, GlobalVar.OpSignalResist, compVal.Val, ref m_CurSignal);
                            WriteSignalLog(a_CurIndex, m_CurSignal, "저항 발생", close, compVal);
                            return m_CurSignal;
                        }
                    }
                }
            }
            return null;
        }

        // 상승을 먹는 시스템과 하락을 먹는 시스템을 감안하여 동시에 2종류의 신호를 수집한다.
        // 각각 수집된 신호는 용도에 맞는 것을 가져다 쓰게 된다.
        public int FindUpDownSignal(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            a_Close = 0.0;
            //EasyTrader.Signal.PriceSignal lastBreakDownSig = m_BreakDownSignalList[m_BreakDownSignalList.Count - 1];
            //EasyTrader.Signal.PriceSignal lastBreakUpSig = m_BreakUpSignalList[m_BreakUpSignalList.Count - 1];
            int resultSig = GlobalVar.BreakNone;
            if (a_ComVal == null || a_Table == null)
                return 0;

            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if ( rowCount < 2)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);
            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 0)
                return resultSig;

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return resultSig;

            DataRow row = a_Table.Rows[prevIndex];
            double preOpen = Convert.ToDouble(row["시가"]);
            double preHigh = Convert.ToDouble(row["고가"]);
            double preLow = Convert.ToDouble(row["저가"]);

            int oldUpDown = GlobalVar.NoneRange;
            
            row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            int curTime = Convert.ToInt32(row["시각"]);
            a_Close = close;
            a_ComVal.DeltaY = close - a_ComVal.Val;

            double tHigh = Math.Max(preHigh, high);
            double tLow = Math.Min(preLow, low);

            // 값에 대한 자체 조사를 먼저 한다.
            if (preOpen > a_ComVal.Val)
            {
                if (tLow <= a_ComVal.Val)
                {
                    if (close > a_ComVal.Val)
                    {
                        // 돌파
                        resultSig = GlobalVar.BreakUp;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                        return resultSig;
                    }
                    else if (close < a_ComVal.Val)
                    {
                        resultSig = GlobalVar.BreakDown;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                        return resultSig;
                    }
                }
            }
            else if (preOpen < a_ComVal.Val)
            {
                if (tHigh >= a_ComVal.Val)
                {
                    if (close < a_ComVal.Val)
                    {
                        // 붕괴
                        resultSig = GlobalVar.BreakDown;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                        return resultSig;
                    }
                    else if (close > a_ComVal.Val)
                    {
                        resultSig = GlobalVar.BreakUp;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                        return resultSig;
                    }
                }
            }
            else
            {
                if (close < a_ComVal.Val)
                {
                    // 붕괴
                    resultSig = GlobalVar.BreakDown;
                    a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                    return resultSig;
                }
                else if (close > a_ComVal.Val)
                {
                    // 돌파
                    resultSig = GlobalVar.BreakUp;
                    a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                    return resultSig;
                }
            }

            /*
            // 먼저 붕괴와 돌파를 검사한다.- 값의 위아래가 중요한 것이 아니라 장 중에 값을 터치 했는지 안했는지가 매우 중요하다.
            if (oldUpDown == GlobalVar.UpRange)
            {
                if (open < a_ComVal.Val) // 시가가 가격 밑에 있을 때 - 이미 붕괴
                {
                    if (close > a_ComVal.Val) // 최소 2번 가격 터치
                    {
                        // 붕괴후 돌파
                        resultSig = GlobalVar.BreakUp;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                        return resultSig;
                    }
                    else if (close < a_ComVal.Val) // 최소 한번 가격 터치
                    {
                        // 붕괴
                        if (high >= a_ComVal.Val)
                        {
                            // 돌파후 붕괴
                            resultSig = GlobalVar.BreakDown;
                            a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                            return resultSig;
                        }
                        else
                        {
                            // 붕괴
                            resultSig = GlobalVar.BreakDown;
                            a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                            return resultSig;
                        }
                    }
                }
                else if (open > a_ComVal.Val) // 시가가 가격 위에 있을 때
                {
                    // 종가가 가격 위에 있을 때
                    if (close > a_ComVal.Val)
                    {
                        if (low <= a_ComVal.Val) // 최소 2번 가격 터치
                        {
                            // 붕괴후 돌파
                            resultSig = GlobalVar.BreakUp;
                            a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                            return resultSig;
                        }
                    }
                    else if (close < a_ComVal.Val) // 종가가 가격 밑에 있을 때 - 최소 한번 가격 터치
                    {
                        // 붕괴
                        resultSig = GlobalVar.BreakDown;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                        return resultSig;
                    }
                }
                else // 시가가 가격과 같을 때 - 이 경우는 종가로만 판단한다.
                {
                    if (close < a_ComVal.Val) // 최소 1번 가격 터치
                    {
                        // 붕괴
                        resultSig = GlobalVar.BreakDown;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                        return resultSig;
                    }
                    else if (close > a_ComVal.Val) // 최소 1번 가격 터치
                    {
                        // 돌파
                        resultSig = GlobalVar.BreakUp;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                        return resultSig;
                    }
                }
            }
            else if (oldUpDown == GlobalVar.DownRange)
            {
                if (open < a_ComVal.Val) // 시가가 가격 밑에 있을 때 
                {
                    if (close > a_ComVal.Val) // 이미 가격을 한번 터치 했음
                    {
                        // 돌파
                        resultSig = GlobalVar.BreakUp;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                        return resultSig;
                    }
                    else if (close < a_ComVal.Val)
                    {
                        if (high >= a_ComVal.Val) // 고가가 가격 터치 여부 결정 - 최소 2번 가격 터치
                        {
                            // 돌파 후 붕괴
                            resultSig = GlobalVar.BreakDown;
                            a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                            return resultSig;
                        }
                    }
                }
                else if (open > a_ComVal.Val) // 시가가 가격 위에 있을 때
                {
                    if (close > a_ComVal.Val) // 이미 가격 터치
                    {
                        // 돌파
                        if (low <= a_ComVal.Val)
                        {
                            // 붕괴후 돌파
                            resultSig = GlobalVar.BreakUp;
                            a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                            return resultSig;
                        }
                        else
                        {
                            // 돌파
                            resultSig = GlobalVar.BreakUp;
                            a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                            return resultSig;
                        }
                    }
                    else if (close < a_ComVal.Val) // 이미 가격을 최소 2번 터치
                    {
                        // 돌파 후 붕괴
                        resultSig = GlobalVar.BreakDown;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                        return resultSig;
                    }
                }
                else // 시가가 가격과 같을 때 - 이 경우는 종가로만 판단한다.
                {
                    if (close > a_ComVal.Val) // 가격 1번 터치
                    {
                        // 돌파 
                        resultSig = GlobalVar.BreakUp;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                        return resultSig;
                    }
                    else if (close < a_ComVal.Val) // 가격 1번 터치
                    {
                        // 붕괴
                        resultSig = GlobalVar.BreakDown;
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                        return resultSig;
                    }
                }
            }
            else
            {
                if (close > a_ComVal.Val) // 최소 가격 1번 터치
                {
                    // 돌파
                    resultSig = GlobalVar.BreakUp;
                    a_ComVal.UpdateBreakState(GlobalVar.BreakUp, curTime);
                    return resultSig;
                }
                else if (close < a_ComVal.Val) // 최소 가격 1번 터치
                {
                    // 붕괴
                    resultSig = GlobalVar.BreakDown;
                    a_ComVal.UpdateBreakState(GlobalVar.BreakDown, curTime);
                    return resultSig;
                }
            }
            */

            return resultSig;
        }


        // 저항과 지지 상태를 구분하는 함수 - 오차 범위를 터치하는가 안하는가가 제일 중요하다.
        public int FindResSupSignal(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            a_Close = 0.0;
            int resultSig = GlobalVar.BreakNone;

            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);
            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 0)
                return resultSig;

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return resultSig;
 
            DataRow row = a_Table.Rows[prevIndex];
            double preHigh = Convert.ToDouble(row["고가"]);
            double preLow = Convert.ToDouble(row["저가"]);
            int oldUpDown = GlobalVar.NoneRange;
            

            row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            int curTime = Convert.ToInt32(row["시각"]);

            if (preHigh <= a_ComVal.Val && preHigh >= lowLimit)
            {
                if (high <= a_ComVal.Val && high >= lowLimit)
                {
                    if (a_ComVal.RecentState == GlobalVar.BreakUp || a_ComVal.RecentState == GlobalVar.BreakNone)
                    {
                        if (a_ComVal.RecentState == GlobalVar.BreakNone)
                        {
                            // 저항
                            resultSig = GlobalVar.Resist;
                            a_ComVal.UpdateBreakState(GlobalVar.Resist, curTime);
                            return resultSig;
                        }
                        else
                        {
                            int upDown = FindRecentUpDownRange(a_ComVal.Val, a_Table, a_CurIndex);
                            if (upDown == GlobalVar.DownRange)
                            {
                                // 저항
                                resultSig = GlobalVar.Resist;
                                a_ComVal.UpdateBreakState(GlobalVar.Resist, curTime);
                                return resultSig;
                            }
                        }
                    }
                }
            }

            if (preLow >= a_ComVal.Val && preLow <= highLimit)
            {
                if (low >= a_ComVal.Val && low <= highLimit)
                {
                    if (a_ComVal.RecentState == GlobalVar.BreakDown || a_ComVal.RecentState == GlobalVar.BreakNone)
                    {
                        if (a_ComVal.RecentState == GlobalVar.BreakNone)
                        {
                            resultSig = GlobalVar.Support;
                            a_ComVal.UpdateBreakState(GlobalVar.Support, curTime);
                            return resultSig;
                        }
                        else
                        {
                            int upDown = FindRecentUpDownRange(a_ComVal.Val, a_Table, a_CurIndex);
                            if (upDown == GlobalVar.UpRange)
                            {
                                resultSig = GlobalVar.Support;
                                a_ComVal.UpdateBreakState(GlobalVar.Support, curTime);
                                return resultSig;
                            }
                        }
                    }
                }
            }

            return resultSig;
        }


        // 저항과 지지 상태를 구분하는 함수 - 오차 범위를 터치하는가 안하는가가 제일 중요하다.
        public int FindFullResSupSignal(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            if (OpCode == "201H9242")
            {
                int k = 0;
                k = k + 1;
            }
            a_Close = 0.0;
            int resultSig = GlobalVar.BreakNone;

            double margin = 0.05;//GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);
            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 0)
                return resultSig;

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return resultSig;

            DataRow row = a_Table.Rows[prevIndex];
            double preHigh = Convert.ToDouble(row["고가"]);
            double preLow = Convert.ToDouble(row["저가"]);
            int oldUpDown = GlobalVar.NoneRange;


            row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            a_Close = close;
            int curTime = Convert.ToInt32(row["시각"]);

            int firstIndex = 0;
            int secondIndex = 0;
            int firstUpDown = FindUpDownRange(a_ComVal.Val, a_Table, a_CurIndex, 1, out firstIndex);
            int secondUpDown = FindUpDownRange(a_ComVal.Val, a_Table, a_CurIndex, 2, out secondIndex);
            int underHigh = IsInRange(a_ComVal.Val, a_Table, secondIndex, firstIndex);
            int overLow = IsInRange(a_ComVal.Val, a_Table, secondIndex, firstIndex);
            if (firstIndex == a_CurIndex && firstIndex > secondIndex && (firstIndex - secondIndex) >= 2)
            {
                if (firstUpDown == GlobalVar.DownRange && secondUpDown == GlobalVar.DownRange && underHigh == GlobalVar.InRange && a_ComVal.ResistCount < GlobalVar.CenterTryCount)
                {
                    // 저항
                    resultSig = GlobalVar.Resist;
                    a_ComVal.UpdateBreakState(GlobalVar.Resist, curTime);
                    a_ComVal.ResistCount++;
                    if (a_ComVal.SupportCount > 0)
                        a_ComVal.SupportCount = 0;
                    return resultSig;
                }

                if (firstUpDown == GlobalVar.UpRange && secondUpDown == GlobalVar.UpRange && overLow == GlobalVar.InRange && a_ComVal.SupportCount < GlobalVar.CenterTryCount)
                {
                    resultSig = GlobalVar.Support;
                    a_ComVal.UpdateBreakState(GlobalVar.Support, curTime);
                    a_ComVal.SupportCount++;
                    if (a_ComVal.ResistCount > 0)
                        a_ComVal.ResistCount = 0;
                    return resultSig;
                }
            }

            return resultSig;
        }


        public int FindBendSignal(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            if (OpCode == "301H9242")
            {
                int k = 0;
                k = k + 1;
            }
            a_Close = 0.0;
            int resultSig = GlobalVar.BreakNone;

            double margin = OptBendSysVar.ValMargin;
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 3)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);

            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 2)
                return resultSig;
            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            a_Close = close;
            int curTime = Convert.ToInt32(row["시각"]);

            row = a_Table.Rows[endIndex - 1];
            double preHigh = Convert.ToDouble(row["고가"]);
            double preLow = Convert.ToDouble(row["저가"]);

            row = a_Table.Rows[endIndex - 2];
            double farHigh = Convert.ToDouble(row["고가"]);
            double farLow = Convert.ToDouble(row["저가"]);


            if (preHigh < a_ComVal.Val && farHigh < a_ComVal.Val)
            {
                if (high <= highLimit && high >= lowLimit && close < (a_ComVal.Val - OptBendSysVar.ValMargin))
                {
                    resultSig = GlobalVar.SignalSell;
                    return resultSig;
                }
            }

            if (farHigh < a_ComVal.Val && preHigh == a_ComVal.Val)
            {
                if (high <= highLimit && high >= lowLimit && close < (a_ComVal.Val - OptBendSysVar.ValMargin))
                {
                    resultSig = GlobalVar.SignalSell;
                    return resultSig;
                }
            }


            if (preLow > a_ComVal.Val && farLow > a_ComVal.Val)
            {
                if (low >= lowLimit && low <= highLimit && close > (a_ComVal.Val + OptBendSysVar.ValMargin))
                {
                    resultSig = GlobalVar.SignalBuy;
                    return resultSig;
                }
            }

            if (farLow > a_ComVal.Val && preLow == a_ComVal.Val)
            {
                if (low >= lowLimit && low <= highLimit && close > (a_ComVal.Val + OptBendSysVar.ValMargin))
                {
                    resultSig = GlobalVar.SignalBuy;
                    return resultSig;
                }
            }


            return resultSig;
        }


        public int FindBendSignal2(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            if (OpCode == "301H9242")
            {
                int k = 0;
                k = k + 1;
            }
            a_Close = 0.0;
            int resultSig = GlobalVar.BreakNone;

            double margin = OptBendSysVar.ValMargin;
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 3)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);

            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 2)
                return resultSig;
            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            a_Close = close;
            int curTime = Convert.ToInt32(row["시각"]);

            row = a_Table.Rows[endIndex - 1];
            double preHigh = Convert.ToDouble(row["고가"]);
            double preLow = Convert.ToDouble(row["저가"]);

            row = a_Table.Rows[endIndex - 2];
            double farHigh = Convert.ToDouble(row["고가"]);
            double farLow = Convert.ToDouble(row["저가"]);


            if (preHigh < a_ComVal.Val && farHigh < a_ComVal.Val)
            {
                if (high <= a_ComVal.Val && high >= lowLimit && close < (a_ComVal.Val - 0.05))
                {
                    resultSig = GlobalVar.SignalSell;
                    return resultSig;
                }
            }

            if (farHigh < a_ComVal.Val && preHigh == a_ComVal.Val)
            {
                if (high <= a_ComVal.Val && high >= lowLimit && close < (a_ComVal.Val - 0.05))
                {
                    resultSig = GlobalVar.SignalSell;
                    return resultSig;
                }
            }


            if (preLow > a_ComVal.Val && farLow > a_ComVal.Val)
            {
                if (low >= a_ComVal.Val && low <= highLimit && close > (a_ComVal.Val + 0.05))
                {
                    resultSig = GlobalVar.SignalBuy;
                    return resultSig;
                }
            }

            if (farLow > a_ComVal.Val && preLow == a_ComVal.Val)
            {
                if (low >= a_ComVal.Val && low <= highLimit && close > (a_ComVal.Val + 0.05))
                {
                    resultSig = GlobalVar.SignalBuy;
                    return resultSig;
                }
            }


            return resultSig;
        }


        // 저항과 지지 상태를 구분하는 함수 - 오차 범위를 터치하는가 안하는가가 제일 중요하다.
        public int FindResSupSignalOld(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            a_Close = 0.0;
            int resultSig = GlobalVar.BreakNone;

            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);
            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 0)
                return resultSig;

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return resultSig;
            int farIndex = endIndex - 2;
            if (farIndex < 0)
                return resultSig;

            DataRow row = a_Table.Rows[farIndex];
            double farHigh = Convert.ToDouble(row["고가"]);
            double farLow = Convert.ToDouble(row["저가"]);


            row = a_Table.Rows[prevIndex];
            double preHigh = Convert.ToDouble(row["고가"]);
            double preLow = Convert.ToDouble(row["저가"]);
            int oldUpDown = GlobalVar.NoneRange;


            row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            int curTime = Convert.ToInt32(row["시각"]);

            // 돌파와 지지는 과거 2개 봉 까지 본다.
            if ((farLow >= a_ComVal.Val && farLow <= highLimit) &&
                 (preLow >= a_ComVal.Val && preLow <= highLimit))
            {
                if (open > highLimit)
                {
                    resultSig = GlobalVar.Support;
                    a_ComVal.UpdateBreakState(GlobalVar.Support, curTime);
                    return resultSig;
                }
                else
                {
                    if ((open >= a_ComVal.Val && open <= highLimit) ||
                    (low >= a_ComVal.Val && low <= highLimit))
                    {
                        if (close > highLimit)
                        {
                            resultSig = GlobalVar.Support;
                            a_ComVal.UpdateBreakState(GlobalVar.Support, curTime);
                            return resultSig;
                        }
                    }
                }
            }


            if ((farHigh <= a_ComVal.Val && farHigh >= lowLimit) &&
                 (preHigh <= a_ComVal.Val && preHigh >= lowLimit))
            {
                if (open < lowLimit)
                {
                    resultSig = GlobalVar.Resist;
                    a_ComVal.UpdateBreakState(GlobalVar.Resist, curTime);
                    return resultSig;
                }
                else
                {
                    if ((open <= a_ComVal.Val && open >= lowLimit) ||
                    (high <= a_ComVal.Val && high >= lowLimit))
                    {
                        if (close < lowLimit)
                        {
                            resultSig = GlobalVar.Resist;
                            a_ComVal.UpdateBreakState(GlobalVar.Resist, curTime);
                            return resultSig;
                        }
                    }
                }
            }

            return resultSig;
        }


        private int FindRecentUpDown(double a_Val, DataTable a_Table, int a_CurIndex)
        {
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return GlobalVar.NoneRange;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return GlobalVar.NoneRange;

            for (int i = prevIndex; i >= 0; i--)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if (low > a_Val)
                    return GlobalVar.UpRange;
                else if (high < a_Val)
                    return GlobalVar.DownRange;
            }

            return GlobalVar.NoneRange;
        }

        private int FindRecentUpDownRange(double a_Val, DataTable a_Table, int a_CurIndex)
        {
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return GlobalVar.NoneRange;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return GlobalVar.NoneRange;

            double margin = GlobalVar.CalcOptMargin(a_Val);
            double highLimit = a_Val + margin;
            double lowLimit = a_Val - margin;

            for (int i = prevIndex; i >= 0; i--)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if (low > highLimit)
                    return GlobalVar.UpRange;
                else if (high < lowLimit)
                    return GlobalVar.DownRange;
            }

            return GlobalVar.NoneRange;
        }

        private int FindUpDownRange(double a_Val, DataTable a_Table, int a_CurIndex, int a_BackCount, out int a_Index)
        {
            a_Index = a_CurIndex;
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return GlobalVar.NoneRange;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);


            double margin = 0.05; // GlobalVar.CalcOptMargin(a_Val);
            double highLimit = a_Val + margin;
            double lowLimit = a_Val - margin;

            int upDownCount = 0;

            for (int i = endIndex; i >= 0; i--)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if (low > highLimit)
                {
                    //return GlobalVar.UpRange;
                    upDownCount++;
                    if (upDownCount == a_BackCount)
                    {
                        a_Index = i;
                        return GlobalVar.UpRange;
                    }
                }
                else if (high < lowLimit)
                {
                    //return GlobalVar.DownRange;
                    upDownCount++;
                    if (upDownCount == a_BackCount)
                    {
                        a_Index = i;
                        return GlobalVar.DownRange;
                    }
                }
            }

            return GlobalVar.NoneRange;
        }


        private int IsOverLowLimit(double a_Val, DataTable a_Table, int a_BeginIndex, int a_EndIndex)
        {
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return GlobalVar.NoneRange;

            int beginIndex = a_BeginIndex;
            int endIndex = a_EndIndex;


            double margin = 0.05;// GlobalVar.CalcOptMargin(a_Val);
            double highLimit = a_Val + margin;
            double lowLimit = a_Val - margin;

            for (int i = beginIndex; i <= endIndex; i++)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if (low > highLimit)
                {
                    return GlobalVar.UpRange;
                }
            }

            return GlobalVar.InRange;
        }

        private int IsUnderHighLimit(double a_Val, DataTable a_Table, int a_BeginIndex, int a_EndIndex)
        {
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return GlobalVar.NoneRange;

            int beginIndex = a_BeginIndex;
            int endIndex = a_EndIndex;


            double margin = 0.05;// GlobalVar.CalcOptMargin(a_Val);
            double highLimit = a_Val + margin;
            double lowLimit = a_Val - margin;

            for (int i = beginIndex; i <= endIndex; i++)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if (high < lowLimit)
                {
                    return GlobalVar.DownRange;
                }
            }

            return GlobalVar.InRange;
        }

        private int IsInRange(double a_Val, DataTable a_Table, int a_BeginIndex, int a_EndIndex)
        {
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return GlobalVar.NoneRange;

            int beginIndex = a_BeginIndex;
            int endIndex = a_EndIndex;


            double margin = 0.05;// GlobalVar.CalcOptMargin(a_Val);
            double highLimit = a_Val + margin;
            double lowLimit = a_Val - margin;

            for (int i = beginIndex; i <= endIndex; i++)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if (low > highLimit)
                    return GlobalVar.UpRange;
                if (high < lowLimit)
                    return GlobalVar.DownRange;
            }

            return GlobalVar.InRange;
        }

        // 청산은 마지막 진입 신호와는 값이 달라야 한다. 붕괴 모드에서는 마지막 진입보다 작아야 하고
        // 돌파 모드에서는 마지막 진입보다 값이 커야 청산을 할수가 있다. 같은 값에서는 절대 청산을 할수가 없다.
        public int FindLiqSignal(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex, out double a_Close)
        {
            a_Close = 0.0;
            int resultSig = GlobalVar.BreakNone;
            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return resultSig;
            // 항목의 개수가 2개보다 작으면 신호를 발생하지 않는다.
            int rowCount = a_Table.Rows.Count;
            if (rowCount < 2)
                return resultSig;

            int endIndex = FindExactIndex(a_Table, a_CurIndex);
            // 정확한 인덱스를 찾을 수 없으면 실호를 발생하지 않는다.
            if (endIndex < 0)
                return resultSig;

            int prevIndex = endIndex - 1;
            if (prevIndex < 0)
                return resultSig;

            DataRow row = a_Table.Rows[prevIndex];
            int oldUpDown = FindRecentUpDownRange(a_ComVal.Val, a_Table, a_CurIndex);

            row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double open = Convert.ToDouble(row["시가"]);
            double close = Convert.ToDouble(row["종가"]);
            a_Close = close;
            int curTime = Convert.ToInt32(row["시각"]);

            // 먼저 붕괴와 돌파를 검사한다.- 값의 위아래가 중요한 것이 아니라 장 중에 값을 터치 했는지 안했는지가 매우 중요하다.
            if (oldUpDown == GlobalVar.UpRange)
            {
                if (close <= highLimit)
                {
                    // 하락하면서 청산 가능한 상태
                    resultSig = GlobalVar.LiqDown;


                    Console.WriteLine(">>>>>>Time" + curTime.ToString());
                    Console.WriteLine(">>>>>>close" + close.ToString("F2"));
                    Console.WriteLine(">>>>>>Liq Op Code" + this.OpCode);
                    Console.WriteLine(">>>>>>Val = " + a_ComVal.Val.ToString("F2"));


                    return resultSig;
                }
            }
            else if (oldUpDown == GlobalVar.DownRange)
            {
                if (close >= lowLimit)
                {
                    // 상승하면서 청산 가능한 상태
                    resultSig = GlobalVar.LiqUp;
                    return resultSig;
                }
            }

            return resultSig;
        }

        private void SetBreakVal(EasyTrader.Option.CompVal a_CurComVal, int a_BreakIndex, int a_BreakTime)
        {
            if (m_BreakVal == null)
                return;

            if (a_CurComVal == null)
                return;
            if (a_BreakIndex < 0 || a_BreakTime < 0)
                return;
            // 가격과 상태가 같을 때는 이미 설정이 되어 있으므로 그냥 반환한다.
            if (m_BreakVal.Val == a_CurComVal.Val && m_BreakVal.RecentState == a_CurComVal.RecentState)
                return;
            m_BreakVal.Val = a_CurComVal.Val;
            m_BreakVal.Type = a_CurComVal.Type;
            m_BreakVal.SameType = a_CurComVal.SameType;
            m_BreakVal.RecentState = a_CurComVal.RecentState;
            m_BreakVal.Watcher = a_CurComVal.Watcher;
            //m_BreakVal.BreakTime = a_BreakTime;
            //m_BreakVal.BreakIndex = a_BreakIndex;
            m_BreakVal.BreakCode = this.m_OpCode;
        }
        private EasyTrader.Option.CompVal m_BreakVal = null;
        public EasyTrader.Option.CompVal BreakVal
        {
            get { return m_BreakVal; }
            set { m_BreakVal = value; }
        }
        // 가장 최근의 돌파한 기준값
        private EasyTrader.Option.CompVal m_BreakUpVal = null;
        public EasyTrader.Option.CompVal BreakUpVal
        {
            get { return m_BreakUpVal; }
            set { m_BreakUpVal = value; }
        }
       
        // 가장 최근의 붕괴된 기준값
        private EasyTrader.Option.CompVal m_BreakDownVal = null;
        public EasyTrader.Option.CompVal BreakDownVal
        {
            get { return m_BreakDownVal; }
            set { m_BreakDownVal = value; }
        }
        
        private int m_BreakUpIndex = 0;
        public int BreakUpIndex
        {
            get { return m_BreakUpIndex; }
            set { m_BreakUpIndex = value; }
        }
        private int m_BreakDownIndex = 0;
        public int BreakDownIndex
        {
            get { return m_BreakDownIndex; }
            set { m_BreakDownIndex = value; }
        }
        private int m_BreakUpTime = 0;
        public int BreakUpTime
        {
            get { return m_BreakUpTime; }
            set { m_BreakUpTime = value; }
        }
        private int m_BreakDownTime = 0;
        public int BreakDownTime
        {
            get { return m_BreakDownTime; }
            set { m_BreakDownTime = value; }
        }

        private double m_SigOpen = 0.0;
        public double SigOpen
        {
            get { return m_SigOpen; }
            set { m_SigOpen = value; }
        }
        private double m_SigClose = 0.0;
        public double SigClose
        {
            get { return m_SigClose; }
            set { m_SigClose = value; }
        }
        private double m_SigHigh = 0.0;
        public double SigHigh
        {
            get { return m_SigHigh; }
            set { m_SigHigh = value; }
        }
        private double m_SigLow = 0.0;
        public double SigLow
        {
            get { return m_SigLow; }
            set { m_SigLow = value; }
        }

        public void SetSameValue()
        {
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                CompVal upVal = m_ComValList[i];
                for (int j = 0; j < m_ComValList.Count; j++)
                {
                    CompVal downVal = m_ComValList[j];
                    if (i != j && upVal.Val == downVal.Val)
                    {
                        upVal.SameType = downVal.Type;
                    }
                }
            }
        }

        public void SaveSigValues(int a_CurIndex)
        {
            // 테이블 목록의 인덱스를 찾아 그 값을 저장해 준다.
            int rowCount = m_Table.GetRowCount();
            if (rowCount == 0)
                return;
            int index = FindCurIndex(m_Table, a_CurIndex);
            if (index < 0)
                return;

            DataRow row = m_Table.Rows[index];
            double open = Convert.ToDouble(row["시가"]);
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double close = Convert.ToDouble(row["종가"]);

            m_SigOpen = open;
            m_SigHigh = high;
            m_SigLow = low;
            m_SigClose = close;
        }

        public bool GetClose(int a_CurIndex, out double a_Out)
        {
            a_Out = 0.0;
            // 테이블 목록의 인덱스를 찾아 그 값을 저장해 준다.
            int rowCount = m_Table.GetRowCount();
            if (rowCount == 0)
                return false;
            int index = a_CurIndex;
            if (index < 0)
                index = 0;
            if (index > rowCount - 1)
                index = rowCount - 1;

            DataRow row = m_Table.Rows[index];
           
            double close = Convert.ToDouble(row["종가"]);

            a_Out = close;

            return true;
        }

        public bool GetOHLC(int a_CurIndex, out double a_Open, out double a_High, out double a_Low, out double a_Close)
        {
            a_Open = 0.0;
            a_High = 0.0;
            a_Low = 0.0;
            a_Close = 0.0;
            // 테이블 목록의 인덱스를 찾아 그 값을 저장해 준다.
            int rowCount = m_Table.GetRowCount();
            if (rowCount == 0)
                return false;
            int index = a_CurIndex;
            if (index < 0)
                index = 0;
            if (index > rowCount - 1)
                index = rowCount - 1;

            DataRow row = m_Table.Rows[index];

            a_Close = Convert.ToDouble(row["종가"]);
            a_Open = Convert.ToDouble(row["시가"]);
            a_High = Convert.ToDouble(row["고가"]);
            a_Low = Convert.ToDouble(row["저가"]);


            return true;
        }

        // a_Type : 1 : 고가를 기준으로, -1 : 저가를 기준으로
        public int GetHighLowSameValueCount(int a_CurIndex, int a_Range, int a_Type, out double a_Close)
        {
            a_Close = 0.0;
            int count = 0;
            int endIndex = a_CurIndex;
            int rowCount = m_Table.GetRowCount();
            if (rowCount == 0)
                return 0;
            if (endIndex < 0)
                endIndex = 0;
            endIndex = FindCurIndex(m_Table, endIndex);
            if (endIndex < 0)
                return 0;

            double margin = 0.0;
            if (m_InnerOuter > 0)
            {
                margin = OptPriceSysVar.OuterMargin;
            }
            else if (m_InnerOuter < 0)
            {
                margin = OptPriceSysVar.InnerMargin;
            }


            DataRow row = m_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            double close = Convert.ToDouble(row["종가"]);
            a_Close = close;

            double limitHigh = 0.0;
            double limitLow = 0.0;
            if (a_Type == 1)
            {
                limitHigh = high + margin;
                limitLow = high - margin;
            }
            else
            {
                limitHigh = low + margin;
                limitLow = low - margin;
            }

            int startIndex = endIndex - a_Range;
            if (startIndex < 0)
                startIndex = 0;

            for (int i = startIndex; i <= endIndex; i++)
            {
                row = m_Table.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);
                close = Convert.ToDouble(row["종가"]);
                if (a_Type == 1)
                {
                    if ((high <= limitHigh && high >= limitLow) || 
                        (close<= limitHigh && close >= limitLow))
                    {
                        a_Close = close;
                        count++;
                    }
                }
                else
                {
                    if ((low <= limitHigh && low >= limitLow) ||
                        (close <= limitHigh && close >= limitLow))
                    {
                        a_Close = close;
                        count++;
                    }
                }
            }

            return count;
        }


        private EasyTrader.ETDataSet m_EasyTraderDataSet = null;
        public EasyTrader.ETDataSet EasyTraderDataSet
        {
            get { return m_EasyTraderDataSet; }
            set { m_EasyTraderDataSet = value; }
        }

        private EasyTrader.DataSet.BarDataTable m_Table = null;
        public EasyTrader.DataSet.BarDataTable Table
        {
            get { return m_Table; }
            set { m_Table = value; }
        }

        private string m_OpCode = "";
        public string OpCode
        {
            get { return m_OpCode; }
            set { m_OpCode = value; }
        }

        // 내가 외가 등가, 0 : 등가, -1 : 내가, +1 : 외가
        private int m_InnerOuter = 0;
        public int InnerOuter
        {
            get { return m_InnerOuter; }
            set { m_InnerOuter = value; }
        }

        // 비교할 값들
        private List<CompVal> m_ComValList = new List<CompVal>();
        public List<CompVal> ComValList
        {
            get { return m_ComValList; }
            set { m_ComValList = value; }
        }
        
        public StateWatcher()
        {
            ;
        }

        public void CreateCenterValList(List<EasyTrader.DataSet.SimpleData> a_List)
        {
            for (int i = 0; i < a_List.Count; i++)
            {
                EasyTrader.DataSet.SimpleData data = a_List[i];
                EasyTrader.Option.CompVal com = new EasyTrader.Option.CompVal();
                com.Type = data.CallType;
                com.Val = data.CallVal;
                // 부모 상태 감시자를 넣어 준다.
                com.Watcher = this;
                m_ComValList.Add(com);

                com = new EasyTrader.Option.CompVal();
                com.Type = data.PutType;
                com.Val = data.PutVal;
                // 부모 상태 감시자를 넣어 준다.
                com.Watcher = this;
                m_ComValList.Add(com);
            }

            for (int j = 0; j < ComValList.Count; j++)
            {
                ComValList[j].BreakCode = OpCode;
            }
        }

        public void CreateTypicalValList()
        {
            for (int i = 0; i < 5; i++)
            {
                EasyTrader.Option.CompVal com = new EasyTrader.Option.CompVal();
                com.Type = i;
                com.Val = 0.0;
                // 부모 상태 감시자를 넣어 준다.
                com.Watcher = this;
                m_ComValList.Add(com);
            }

            for (int j = 0; j < ComValList.Count; j++)
            {
                ComValList[j].BreakCode = OpCode;
            }
        }

        // 각 값에 대한 상태의 합을 전달해 준다.
        public int GetStateSum()
        {
            int stateCount = 0;
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                CompVal curState = m_ComValList[i];
                stateCount += curState.RecentState;
            }

            return stateCount;
        }

        // 상태를 파악하는 시작 인덱스이다.
        private int m_StartIndex = 0;
        public int StartIndex
        {
            get { return m_StartIndex; }
            set { m_StartIndex = value; }
        }

        // 신호가 발생했을 때의 고점이나 저점의 인덱스를 찾아 시작 인덱스로 등록해 준다.
        // a_Type : 1 : 돌파, -1 : 붕괴
        public void SetStartIndex(int a_CurIndex, int a_Type)
        {
            int highIndex = 0, lowIndex = 0;
            bool result = GetHLIndex(m_Table, m_StartIndex, a_CurIndex, ref highIndex, ref lowIndex);
            if (result == true)
            {
                // 돌파시 시작 인덱스는 저점의 인덱스로 맞춰 준다.
                if (a_Type == 1)
                {
                    m_StartIndex = lowIndex;
                }
                else if (a_Type == -1) // 붕괴시 시작 인덱스는 고점의 인덱스를 맞춰준다.
                {
                    m_StartIndex = highIndex;
                }
            }
        }
        // 모든 상태를 초기화 시킨다.
        public void ClearState()
        {
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                CompVal curState = m_ComValList[i];
                curState.InitBreakState();
            }
        }

        public void UpdateTargetValue(int a_CurIndex, double a_Close)
        {
            // 비교할 값들을 불러와서 종가와의 차이를 넣어 준다.
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                EasyTrader.Option.CompVal curComVal = m_ComValList[i];
                // 목표가에서 현재가를 빼준다.
                curComVal.DeltaTarget = curComVal.Val - a_Close;
            }
        }

        /*
        public void UpdateState(int a_CurIndex)
        {
            // 현재 내가인지 외가인지 결정해 준다.
            m_InnerOuter = m_EasyTraderDataSet.DownLoader.FindInnerOuter(m_OpCode.ToString());
            UpdateBreakUpState(a_CurIndex);
            UpdateBreakDownState(a_CurIndex);
        }*/

        public void UpdateState(int a_CurIndex)
        {
            // 현재 내가인지 외가인지 결정해 준다.
            m_InnerOuter = m_EasyTraderDataSet.DownLoader.FindInnerOuter(m_OpCode.ToString());

            // 일단 일간 시고저종이 필요하다.- 계산가능
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            bool result = GetOHLC(m_Table, m_StartIndex, a_CurIndex, ref open, ref high, ref low, ref close);
            if (result == true)
            {
                // 현재가와 목표가와의 차이를 넣어 준다.
                UpdateTargetValue(a_CurIndex, close);
                int firstBreakTime = -1, recentBreakTime = -1;
                int firstState = GlobalVar.BreakNone, recentState = GlobalVar.BreakNone;

                // 비교할 값들을 불러와서 하나씩 비교해서 상태를 업데이트 해준다.
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal curComVal = m_ComValList[i];
                    curComVal.CurVal = close;
                    //int breakIndex = FindRecentBreakIndex(m_Table, a_CurIndex, curComVal.Val, out min, out max);
                    double margin = GlobalVar.CalcOptMargin(curComVal.Val);
                    double highLimit = curComVal.Val + margin;
                    double lowLimit = curComVal.Val - margin;

                    int rState = FindBreakTime(m_Table, a_CurIndex, highLimit, lowLimit, out firstState, out firstBreakTime, out recentState, out recentBreakTime);
                    if (rState > 0)
                    {
                        if (recentState != GlobalVar.BreakNone)
                        {
                            curComVal.CurVal = close;
                            m_BreakVal = curComVal;
                            curComVal.FirstBreakTime = firstBreakTime;
                            curComVal.RecentState = recentState;
                            curComVal.RecentBreakTime = recentBreakTime;
                            curComVal.FirstState = firstState;
                        }
                    }
                }
            }
        }

        public void UpdateSignal(int a_CurIndex)
        {
            //FindLiqSignal(a_CurIndex, GlobalVar.OpSignalModeBreakDown);
            //FindLiqSignal(a_CurIndex, GlobalVar.OpSignalModeBreakUp);

            FindUpDownSignal(a_CurIndex, GlobalVar.OpSignalModeBreakDown);
            FindUpDownSignal(a_CurIndex, GlobalVar.OpSignalModeBreakUp);

            FindResSupSignal(a_CurIndex, GlobalVar.OpSignalModeBreakDown);
            FindResSupSignal(a_CurIndex, GlobalVar.OpSignalModeBreakUp);
        }

        public void UpdateOHLSignal(int a_CurIndex)
        {
            ;
        }

        public void UpdateState(int a_CurIndex, int a_StartTime)
        {
            // 현재 내가인지 외가인지 결정해 준다.
            m_InnerOuter = m_EasyTraderDataSet.DownLoader.FindInnerOuter(m_OpCode.ToString());

            // 일단 일간 시고저종이 필요하다.- 계산가능
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            bool result = GetOHLC(m_Table, m_StartIndex, a_CurIndex, ref open, ref high, ref low, ref close);
            if (result == true)
            {
                // 현재가와 목표가와의 차이를 넣어 준다.
                UpdateTargetValue(a_CurIndex, close);

                // 비교할 값들을 불러와서 하나씩 비교해서 상태를 업데이트 해준다.
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal curComVal = m_ComValList[i];
                    curComVal.CurVal = close;
                    curComVal.DeltaY = close - curComVal.Val;
                    FindBreakTime(m_Table, a_CurIndex, a_StartTime, ref curComVal);
                }
            }
        }

        private void FindBreak(EasyTrader.Option.CompVal a_ComVal, int a_CurTime, double a_Open, double a_High, double a_Low, double a_Close)
        {
            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;
            if (a_Open > highLimit)
            {
                if (a_Low < a_ComVal.Val)
                {
                    if (a_Close > a_ComVal.Val) // 붕괴후 돌파
                    {
                        // 시간, 상태를 갱신한다.
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, a_CurTime);
                    }
                    else if (a_Close < a_ComVal.Val) // 완전 붕괴
                    {
                        // 시간, 상태를 갱신한다.
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, a_CurTime);
                    }
                }
                else
                {
                    if (a_Low <= highLimit)
                    {
                        if (a_Close > highLimit) // 지지후 돌파
                        {
                            // 시간, 상태를 갱신한다.
                            a_ComVal.UpdateBreakState(GlobalVar.BreakUp, a_CurTime);
                        }
                    }
                }
            }
            else if (a_Open < lowLimit)
            {
                if (a_High > a_ComVal.Val)
                {
                    if (a_Close > a_ComVal.Val) // 완전 돌파
                    {
                        // 시간, 상태를 갱신한다.
                        a_ComVal.UpdateBreakState(GlobalVar.BreakUp, a_CurTime);
                    }
                    else if (a_Close < a_ComVal.Val) // 돌파 후 붕괴
                    {
                        // 시간, 상태를 갱신한다.
                        a_ComVal.UpdateBreakState(GlobalVar.BreakDown, a_CurTime);
                    }
                }
                else
                {
                    if (a_High >= lowLimit)
                    {
                        if (a_Close < lowLimit) // 저항 후 붕괴
                        {
                            // 시간, 상태를 갱신한다.
                            a_ComVal.UpdateBreakState(GlobalVar.BreakDown, a_CurTime);
                        }
                    }
                }
            }
            else
            {
                if (a_Close > a_ComVal.Val) // 돌파
                {
                    // 시간, 상태를 갱신한다.
                    a_ComVal.UpdateBreakState(GlobalVar.BreakUp, a_CurTime);
                }
                else if (a_Close < a_ComVal.Val) // 붕괴
                {
                    // 시간, 상태를 갱신한다.
                    a_ComVal.UpdateBreakState(GlobalVar.BreakDown, a_CurTime);
                }
            }
        }


        private void FindRange(EasyTrader.Option.CompVal a_ComVal, DataTable a_Table, int a_CurIndex)
        {
            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            if (a_Table == null)
                return;
            if (a_Table.Rows.Count == 0)
                return;

            int endIndex = FindCurIndex(a_Table, a_CurIndex);
            if (endIndex < 0)
                return;
            int curRange = GlobalVar.NoneRange;
            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            int curTime = Convert.ToInt32(row["시각"]);
            if (low > highLimit)
                curRange = GlobalVar.UpRange;
            else if (high < lowLimit)
                curRange = GlobalVar.DownRange;
            else
                curRange = GlobalVar.InRange;
            if (curRange != GlobalVar.NoneRange && OldRange != GlobalVar.NoneRange)
            {
                if (curRange != OldRange)
                {
                    if (OldRange == GlobalVar.DownRange)
                    {
                        if (curRange == GlobalVar.InRange || curRange == GlobalVar.UpRange)
                        {
                            if (a_ComVal.FirstUpInState == GlobalVar.NoneRange)
                            {
                                a_ComVal.FirstUpInState = GlobalVar.InUpRange;
                                a_ComVal.FirstUpInTime = curTime;
                            }
                            a_ComVal.RecentRange = GlobalVar.InUpRange;
                            a_ComVal.RecentRangeTime = curTime;
                        }
                    }
                    else if (OldRange == GlobalVar.UpRange)
                    {
                        if (curRange == GlobalVar.InRange || curRange == GlobalVar.DownRange)
                        {
                            if (a_ComVal.FirstDownInState == GlobalVar.NoneRange)
                            {
                                a_ComVal.FirstDownInState = GlobalVar.InDownRange;
                                a_ComVal.FirstDownInTime = curTime;
                            }
                            a_ComVal.RecentRange = GlobalVar.InDownRange;
                            a_ComVal.RecentRangeTime = curTime;
                        }
                    }
                }
            }
            OldRange = curRange;
        }

        public void UpdateState2(int a_CurIndex, int a_StartTime)
        {
            // 일단 일간 시고저종이 필요하다.- 계산가능
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            int endTime = GlobalVar.DayIndexToTime(a_CurIndex);
            bool result = GetOHLCByTime(m_Table, a_StartTime, endTime, ref open, ref high, ref low, ref close);
            if (result == true)
            {
                // 현재가와 목표가와의 차이를 넣어 준다.
                UpdateTargetValue(a_CurIndex, close);

                // 비교할 값들을 불러와서 하나씩 비교해서 상태를 업데이트 해준다.
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal curComVal = m_ComValList[i];
                    curComVal.CurVal = close;
                    curComVal.DeltaY = close - curComVal.Val;
                    // 돌파 붕괴를 조사한다.
                    FindBreak(curComVal, endTime, open, high, low, close);
                    // 범위에 들어 왔는지 조사한다.
                    FindRange(curComVal, m_Table, a_CurIndex);
                }
            }
        }

        // 이 함수는 테이블 이름과 현재 코드 이름이 일치하는지 확인한다.
        // 일치하지 않으면 일치시키고 비교값들을 다시 설정해 준다.
        public void CheckTableSync(int a_Date, EasyTrader.Signal.TotalSignalManager a_SigMan)
        {
            if (m_Table == null || a_SigMan == null)
                return;

            string tableName = m_Table.TableName;
            if (tableName != m_OpCode)
            {
                m_OpCode = tableName;
                ResetDDEInfo(a_Date, a_SigMan);
            }
        }

        public void ResetDDEInfo(int a_Date, EasyTrader.Signal.TotalSignalManager a_SigMan)
        {
            if (m_Table == null || a_SigMan == null)
                return;

            EasyTrader.Option.DDEData dde = a_SigMan.EasyTraderDataSet.FindDDEData(a_Date, OpCode);
            string sideCode = OpCode.Substring(0, 1);
            string priceCode = OpCode.Substring(OpCode.Length - 3, 3);
            int priceVal = Convert.ToInt32(priceCode);
            if (sideCode == "2")
            {
                ComValList[0].Val = Convert.ToDouble(dde.DataItem.PutMLow.ToString()); // 상대월저
                ComValList[0].Type = 0;
                ComValList[0].Price = priceVal;
                ComValList[1].Val = dde.PutJoint; // 최신상대마디
                ComValList[1].Type = 1;
                ComValList[1].Price = priceVal;
                ComValList[2].Val = Convert.ToDouble(dde.DataItem.PutBase.ToString()); // 상대기준
                ComValList[2].Type = 2;
                ComValList[2].Price = priceVal;
                ComValList[3].Val = dde.PutTarget; // 최신상대목표
                ComValList[3].Type = 3;
                ComValList[3].Price = priceVal;
                ComValList[4].Val = Convert.ToDouble(dde.DataItem.PutMHigh.ToString()); // 상대월고
                ComValList[4].Type = 4;
                ComValList[4].Price = priceVal;
                m_CounterMonthHigh = ComValList[4].Val;
                SetSameValue();
            }
            if (sideCode == "3")
            {
                ComValList[0].Val = Convert.ToDouble(dde.DataItem.CallMLow.ToString()); // 상대월저
                ComValList[0].Type = 0;
                ComValList[0].Price = priceVal;
                ComValList[1].Val = dde.CallJoint; // 최신상대마디
                ComValList[1].Type = 1;
                ComValList[1].Price = priceVal;
                ComValList[2].Val = Convert.ToDouble(dde.DataItem.CallBase.ToString()); // 상대기준
                ComValList[2].Type = 2;
                ComValList[2].Price = priceVal;
                ComValList[3].Val = dde.CallTarget; // 최신상대목표
                ComValList[3].Type = 3;
                ComValList[3].Price = priceVal;
                ComValList[4].Val = Convert.ToDouble(dde.DataItem.CallMHigh.ToString()); // 상대월고
                ComValList[4].Type = 4;
                ComValList[4].Price = priceVal;
                m_CounterMonthHigh = ComValList[4].Val;
                SetSameValue();
            }
            for (int j = 0; j < ComValList.Count; j++)
            {
                ComValList[j].BreakCode = OpCode;
            }
        }

        // 돌파 상태를 확인한다. 돌파는 작은 값부터 이루어 지므로 작은 값부터 먼저 조사를 한다.
        public void UpdateBreakUpState(int a_CurIndex)
        {
            // 일단 일간 시고저종이 필요하다.- 계산가능
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            bool result = GetOHLC(m_Table, m_StartIndex, a_CurIndex, ref open, ref high, ref low, ref close);
            if (result == true)
            {
                // 현재가와 목표가와의 차이를 넣어 준다.
                UpdateTargetValue(a_CurIndex, close);

                // 비교할 값들을 불러와서 하나씩 비교해서 상태를 업데이트 해준다.
                for (int i = 0; i < m_ComValList.Count; i++)
                {
                    EasyTrader.Option.CompVal curComVal = m_ComValList[i];
                    // 비교할 값이 0일 때는 아무일도 하지 않는다.
                    if (curComVal.Val == 0.0)
                        continue;
                    // 외가와 내가를 구분하여 마진을 더해 준다.
                    double upperLimitVal = curComVal.Val;
                    double lowerLimitVal = curComVal.Val;


                    if (m_InnerOuter > 0)
                    {
                        upperLimitVal += OptPriceSysVar.OuterMargin;
                        lowerLimitVal -= OptPriceSysVar.OuterMargin;
                    }
                    else if (m_InnerOuter < 0)
                    {
                        upperLimitVal += OptPriceSysVar.InnerMargin;
                        lowerLimitVal -= OptPriceSysVar.InnerMargin;
                    }

                    double openHighLimit = curComVal.Val;
                    double openLowLimit = curComVal.Val;
                    if (m_InnerOuter > 0)
                    {
                        openHighLimit += OptPriceSysVar.OuterMargin;
                        openLowLimit -= OptPriceSysVar.OuterMargin;
                    }
                    else if (m_InnerOuter < 0)
                    {
                        openHighLimit += OptPriceSysVar.InnerMargin;
                        openLowLimit -= OptPriceSysVar.InnerMargin;
                    }

                    if (OpCode == "301H7240")
                    {
                        int p = 0;
                        p = p + 1;
                    }

                    // 시가가 비교값보다 큰 경우. 이경우는 붕괴만을 조사한다.
                    if (openHighLimit < open)
                    {
                        // 비교값보다 저가가 더 작은 경우
                        if (openLowLimit > low)
                        {
                            // // 비교값보다 종가가 크거나 같은 경우 - 이 경우 붕괴 후 돌파 
                            if (curComVal.Val <= close)
                            {
                                curComVal.UpdateBreakState(1, a_CurIndex, GlobalVar.DayIndexToTime(a_CurIndex));
                                m_BreakVal = curComVal;

                                if (OpCode == "301H7240")
                                {
                                    int p = 0;
                                    p = p + 1;
                                }
                            }
                        }
                    }
                    else if (openLowLimit > open) // 시가가 비교값 보다 작은 경우. 이 경우 돌파 만을 조사한다.
                    {
                        // 비교값보다 고가가 더 큰 경우 
                        if (openHighLimit < high)
                        {
                            // 비교값보다 종가가 더 큰 경우 - 완전 돌파
                            if (curComVal.Val < close)
                            {
                                curComVal.UpdateBreakState(1, a_CurIndex, GlobalVar.DayIndexToTime(a_CurIndex));
                                m_BreakVal = curComVal;

                                if (OpCode == "301H7240")
                                {
                                    int p = 0;
                                    p = p + 1;
                                }
                            }
                        }
                    }
                    else // 시가가 비교값과 같은 경우 - 이 경우는 돌파나 붕괴를 모두 조사한다.
                    {
                        // 이 경우 종가만을 가지고 판단을 한다.
                        if (openHighLimit <= close)
                        {
                            // 종가가 비교값보다 클 경우 이므로 돌파
                            curComVal.UpdateBreakState(1, a_CurIndex, GlobalVar.DayIndexToTime(a_CurIndex));
                            m_BreakVal = curComVal;

                            if (OpCode == "301H7240")
                            {
                                int p = 0;
                                p = p + 1;
                            }
                        }
                        else // 이상태는 현재 아무 상태도 아니다.
                        {
                            curComVal.RecentState = 0;
                            //curComVal.BreakIndex = 0;
                            //curComVal.BreakTime = 0;
                        }
                    }
                }
                
            }
        }

        // 붕괴 상태를 확인한다. 붕괴는 큰 값부터 이루어 지므로 큰 값부터 먼저 확인한다.
        public void UpdateBreakDownState(int a_CurIndex)
        {
            // 일단 일간 시고저종이 필요하다.- 계산가능
            double open = 0.0, high = 0.0, low = 0.0, close = 0.0;
            bool result = GetOHLC(m_Table, m_StartIndex, a_CurIndex, ref open, ref high, ref low, ref close);
            if (result == true)
            {
                // 현재가와 목표가와의 차이를 넣어 준다.
                UpdateTargetValue(a_CurIndex, close);

                // 비교할 값들을 불러와서 하나씩 비교해서 상태를 업데이트 해준다.
                for (int i = m_ComValList.Count - 1; i >= 0; i--)
                {
                    EasyTrader.Option.CompVal curComVal = m_ComValList[i];
                    // 비교할 값이 0일 때는 아무일도 하지 않는다.
                    if (curComVal.Val == 0.0)
                        continue;
                    // 외가와 내가를 구분하여 마진을 더해 준다.
                    double upperLimitVal = curComVal.Val;
                    double lowerLimitVal = curComVal.Val;


                    if (m_InnerOuter > 0)
                    {
                        upperLimitVal += OptPriceSysVar.OuterMargin;
                        lowerLimitVal -= OptPriceSysVar.OuterMargin;
                    }
                    else if (m_InnerOuter < 0)
                    {
                        upperLimitVal += OptPriceSysVar.InnerMargin;
                        lowerLimitVal -= OptPriceSysVar.InnerMargin;
                    }

                    double openHighLimit = curComVal.Val;
                    double openLowLimit = curComVal.Val;
                    if (m_InnerOuter > 0)
                    {
                        openHighLimit += OptPriceSysVar.OuterMargin;
                        openLowLimit -= OptPriceSysVar.OuterMargin;
                    }
                    else if (m_InnerOuter < 0)
                    {
                        openHighLimit += OptPriceSysVar.InnerMargin;
                        openLowLimit -= OptPriceSysVar.InnerMargin;
                    }

                    if (OpCode == "301H7240")
                    {
                        int p = 0;
                        p = p + 1;
                    }

                    // 시가가 비교값보다 큰 경우. 이경우는 붕괴만을 조사한다.
                    if (openHighLimit < open)
                    {
                        // 비교값보다 저가가 더 작은 경우
                        if (openLowLimit > low)
                        {
                            // 비교값보다 종가가 작은 경우 - 완전 붕괴
                            if (curComVal.Val > close)
                            {
                                curComVal.UpdateBreakState(-1, a_CurIndex, GlobalVar.DayIndexToTime(a_CurIndex));
                                m_BreakVal = curComVal;
                                if (OpCode == "301H7240")
                                {
                                    int p = 0;
                                    p = p + 1;
                                }
                            }
                        }
                    }
                    else if (openLowLimit > open) // 시가가 비교값 보다 작은 경우. 이 경우 돌파 만을 조사한다.
                    {
                        // 비교값보다 고가가 더 큰 경우 
                        if (openHighLimit < high)
                        {
                            // 비교값보다 종가가 작거나 같은 경우. 이경우 돌파후 붕괴이다.
                            if (curComVal.Val >= close)
                            {
                                curComVal.UpdateBreakState(-1, a_CurIndex, GlobalVar.DayIndexToTime(a_CurIndex));
                                m_BreakVal = curComVal;
                                if (OpCode == "301H7240")
                                {
                                    int p = 0;
                                    p = p + 1;
                                }
                            }
                        }
                    }
                    else // 시가가 비교값과 같은 경우 - 이 경우는 붕괴를 조사한다.
                    {
                        if (openLowLimit >= close)
                        {
                            // 종가가 비교값보다 작을 경우 이므로 붕괴
                            curComVal.UpdateBreakState(-1, a_CurIndex, GlobalVar.DayIndexToTime(a_CurIndex));
                            m_BreakVal = curComVal;
                            if (OpCode == "301H7240")
                            {
                                int p = 0;
                                p = p + 1;
                            }
                        }
                    }
                }
            }
        }


        private bool GetHLIndex(DataTable a_Table, int a_StartIndex, int a_EndIndex, ref int a_HighIndex, ref int a_LowIndex)
        {
            if (a_Table == null)
                return false;
            if (a_Table.Rows.Count == 0)
                return false;
            if (a_StartIndex < 0 || a_StartIndex > a_Table.Rows.Count - 1)
                return false;
            if (a_StartIndex > a_EndIndex || a_EndIndex < 0)
                return false;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return false;

            DataRow row = a_Table.Rows[a_StartIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            a_HighIndex = -1;
            a_LowIndex = -1;
            for (int i = m_StartIndex; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double curHigh = Convert.ToDouble(row["고가"]);
                double curLow = Convert.ToDouble(row["저가"]);
                if (high > curHigh)
                {
                    high = curHigh;
                    a_HighIndex = i;
                }
                if (low < curLow)
                {
                    low = curLow;
                    a_LowIndex = i;
                }
            }
            return true;
        }

        private bool GetOHLC(DataTable a_Table, int a_StartIndex, int a_EndIndex, ref double a_Open, ref double a_High, ref double a_Low, ref double a_Close)
        {
            if (a_Table == null)
                return false;
            if (a_Table.Rows.Count == 0)
                return false;
            if (a_StartIndex < 0 || a_StartIndex > a_Table.Rows.Count - 1)
                return false;
            if (a_StartIndex > a_EndIndex || a_EndIndex < 0)
                return false;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return false;

            
            DataRow row = a_Table.Rows[a_StartIndex];
            a_Open = Convert.ToDouble(row["시가"]);
            a_High = Convert.ToDouble(row["고가"]);
            a_Low = Convert.ToDouble(row["저가"]);
            for (int i = a_StartIndex; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                a_Close = Convert.ToDouble(row["종가"]);
                if (high > a_High)
                    a_High = high;
                if (low < a_Low)
                    a_Low = low;
            }
            return true;
        }

        public bool GetOHLC(int a_StartIndex, int a_EndIndex, ref double a_Open, ref double a_High, ref double a_Low, ref double a_Close)
        {
            DataTable a_Table = m_Table;

            if (a_Table == null)
                return false;
            if (a_Table.Rows.Count == 0)
                return false;
            if (a_StartIndex < 0 || a_StartIndex > a_Table.Rows.Count - 1)
                return false;
            if (a_StartIndex > a_EndIndex || a_EndIndex < 0)
                return false;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return false;


            DataRow row = a_Table.Rows[a_StartIndex];
            a_Open = Convert.ToDouble(row["시가"]);
            a_High = Convert.ToDouble(row["고가"]);
            a_Low = Convert.ToDouble(row["저가"]);
            for (int i = a_StartIndex; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                a_Close = Convert.ToDouble(row["종가"]);
                if (high > a_High)
                    a_High = high;
                if (low < a_Low)
                    a_Low = low;
            }
            return true;
        }

        private bool GetOHLCByTime(DataTable a_Table, int a_StartTime, int a_EndTime, ref double a_Open, ref double a_High, ref double a_Low, ref double a_Close)
        {
            if (a_Table == null)
                return false;
            if (a_Table.Rows.Count == 0)
                return false;
            a_High = -999.0;
            a_Low = 999.0;
            bool first = false;
            for (int i = 0; i < a_Table.Rows.Count; i++)
            {
                DataRow row = a_Table.Rows[i];
                int curTime = Convert.ToInt32(row["시각"]);
                double open = Convert.ToDouble(row["시가"]);
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                a_Close = Convert.ToDouble(row["종가"]);
                // 시작시간보다 작을 때는 그냥 넘어간다.
                if (curTime < a_StartTime)
                    continue;
                // 시작 시간과 같을 때는 시가를 확보한다.
                if (first == false && curTime >= a_StartTime)
                {
                    a_Open = open;
                    first = true;
                }

                if (high > a_High)
                    a_High = high;
                if (low < a_Low)
                    a_Low = low;

                // 종료 시간보다 클 때는 탈출한다.
                if (curTime >= a_EndTime)
                    break;
            }
            return true;
        }

        private int GetCrossCount(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int count = 0;


            for (int i = 0; i <= endIndex; i++)
            {
                DataRow row = a_Table.Rows[i];
                double low = Convert.ToDouble(row["저가"]);
                double high = Convert.ToDouble(row["고가"]);
                if (a_CompVal <= high && a_CompVal >= low)
                    count++;
            }
            return count;
        }

        private int FindFirstBreakDownTime(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;

            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            if (a_CompVal <= open)
            {
                for (int i = 0; i < endIndex; i++)
                {
                    row = a_Table.Rows[i];
                    double low = Convert.ToDouble(row["저가"]);
                    double close = Convert.ToDouble(row["종가"]);

                    if (low < a_CompVal || close < a_CompVal)
                    {
                        breakUpTime = Convert.ToInt32(row["시각"]);
                        break;
                    }
                }
            }
            return breakUpTime;
        }


        private int FindRecentBreakDownTime(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[endIndex];
            double close = Convert.ToDouble(row["종가"]);
            if (close < a_CompVal)
            {
                for (int i = endIndex; i >= 0; i--)
                {
                    row = a_Table.Rows[i];
                    double open = Convert.ToDouble(row["시가"]);
                    double high = Convert.ToDouble(row["고가"]);
                    if (open >= a_CompVal || high >= a_CompVal)
                    {
                        breakUpTime = Convert.ToInt32(row["시각"]);
                        break;
                    }
                }
            }
            return breakUpTime;
        }


        public int FindRecentBreakIn(int a_CurIndex)
        {
            for (int i = 0; i < m_ComValList.Count; i++)
            {
                EasyTrader.Option.CompVal curVal = m_ComValList[i];
                int sig = FindRecentBreakIn(a_CurIndex, curVal.Val);
                if (sig == GlobalVar.FromUp || sig == GlobalVar.FromDown)
                {
                    return sig;
                }
            }

            return GlobalVar.FromNone;
        }


        public int FindRecentBreakIn(int a_EndIndex, double a_CompVal)
        {
            EasyTrader.DataSet.BarDataTable a_Table = m_Table;
            if (a_Table == null)
                return GlobalVar.FromNone;
            if (a_Table.Rows.Count == 0)
                return GlobalVar.FromNone;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return GlobalVar.FromNone;

            int breakIn = GlobalVar.FromNone;

            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);

            int recentUpDown = FindRecentUpDownRange(a_CompVal, a_Table, a_EndIndex);

            if (recentUpDown == GlobalVar.UpRange)
            {
                if (a_CompVal <= high && a_CompVal >= low)
                {
                    return GlobalVar.FromUp;
                }
            }
            else if (recentUpDown == GlobalVar.DownRange)
            {
                if (a_CompVal <= high && a_CompVal >= low)
                {
                    return GlobalVar.FromDown;
                }
            }


            return breakIn;
        }

        private int FindFirstBreakUpTime(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);

            if (open < a_CompVal)
            {
                for (int i = 0; i < endIndex; i++)
                {
                    row = a_Table.Rows[i];
                    double high = Convert.ToDouble(row["고가"]);
                    double close = Convert.ToDouble(row["종가"]);
                    if (close >= a_CompVal || high >= a_CompVal)
                    {
                        breakUpTime = Convert.ToInt32(row["시각"]);
                        break;
                    }
                }
            }
            
            return breakUpTime;
        }

        private int FindRecentBreakUpTime(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[endIndex];
            double close = Convert.ToDouble(row["종가"]);
            if (close > a_CompVal)
            {
                for (int i = endIndex; i >= 0; i--)
                {
                    row = a_Table.Rows[i];
                    double open = Convert.ToDouble(row["시가"]);
                    double low = Convert.ToDouble(row["저가"]);
                    if (open <= a_CompVal || low <= a_CompVal)
                    {
                        breakUpTime = Convert.ToInt32(row["시각"]);
                        break;
                    }
                }
            }
            return breakUpTime;
        }


        private int FindRecentBreakTime(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);

            int curPos = 0;
            if (a_CompVal < low)
                curPos = 1;
            else if (a_CompVal > high)
                curPos = -1;
            else
            {
                curPos = 0;
                breakUpTime = Convert.ToInt32(row["시각"]);
                return breakUpTime;
            }
            int oldPos = curPos;
            for (int i = endIndex; i >= 0; i--)
            {
                row = a_Table.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);

                if (high >= a_CompVal && low <= a_CompVal)
                {
                    breakUpTime = Convert.ToInt32(row["시각"]);
                    break;
                }
            }
            return breakUpTime;
        }

        private int FindRecentBreakTime(DataTable a_Table, int a_EndIndex, double a_HighLimit, double a_LowLimit)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            
            
            for (int i = endIndex; i >= 0; i--)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);

                // 고가나 저가가 범위 내에 있으면 만난것으로 한다.
                if ((high <= a_HighLimit && high >= a_LowLimit) ||
                    (low <= a_HighLimit && low >= a_LowLimit))
                {
                    breakUpTime = Convert.ToInt32(row["시각"]);
                    break;
                }
            }
            return breakUpTime;
        }

        private int FindRecentState(DataTable a_Table, int a_EndIndex, double a_HighLimit, double a_LowLimit, out int a_BreakTime)
        {
            a_BreakTime = -1;

            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int recentState = GlobalVar.BreakNone;

            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.BreakNone;

            if (open > a_HighLimit)
                curState = GlobalVar.UpRange;
            else if (open < a_LowLimit)
                curState = GlobalVar.DownRange;
            else
                curState = GlobalVar.InRange;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);

                if (low > a_HighLimit)
                    curState = GlobalVar.UpRange;
                else if (high < a_LowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                    }
                    else
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }

                    a_BreakTime = Convert.ToInt32(row["시각"]);

                    int k = 0;
                    k = k + 1;
                }

                oldState = curState;
            }
            return recentState;
        }


        private int FindBreakTime(DataTable a_Table, int a_EndIndex, double a_HighLimit, double a_LowLimit, out int a_FirstState, out int a_FirstBreakTime, out int a_RecentState, out int a_RecentBreakTime)
        {
            a_RecentBreakTime = -1;
            a_RecentState = GlobalVar.BreakNone;
            a_FirstState = GlobalVar.BreakNone;
            a_FirstBreakTime = -1;

            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int recentState = GlobalVar.BreakNone;

            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.NoneRange;

            if (open > a_HighLimit)
                curState = GlobalVar.UpRange;
            else if (open < a_LowLimit)
                curState = GlobalVar.DownRange;
            else
                curState = GlobalVar.InRange;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                double close = Convert.ToDouble(row["종가"]);

                if (low > a_HighLimit)
                    curState = GlobalVar.UpRange;
                else if (high < a_LowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                    }
                    else if (oldState == GlobalVar.InRange)
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }

                    if (a_FirstBreakTime == -1)
                    {
                        a_FirstBreakTime = Convert.ToInt32(row["시각"]);
                        a_FirstState = recentState;
                    }
                    a_RecentBreakTime = Convert.ToInt32(row["시각"]);
                    a_RecentState = recentState;

                    int k = 0;
                    k = k + 1;
                }
                else // 상태가 같을 경우 - 이때는 종가로만 판단을 한다. 종가가 상한선을 넘으면 돌파, 종가가 하한선을 넘으면 붕괴
                {
                    if (oldState == GlobalVar.InRange && curState == GlobalVar.InRange)
                    {
                        if (close < a_LowLimit)
                        {
                            recentState = GlobalVar.BreakDown;
                            a_RecentBreakTime = Convert.ToInt32(row["시각"]);
                            a_RecentState = recentState;
                            if (a_FirstBreakTime == -1)
                            {
                                a_FirstBreakTime = Convert.ToInt32(row["시각"]);
                                a_FirstState = recentState;
                            }
                        }
                        else if (close > a_HighLimit)
                        {
                            recentState = GlobalVar.BreakUp;
                            a_RecentBreakTime = Convert.ToInt32(row["시각"]);
                            a_RecentState = recentState;
                            if (a_FirstBreakTime == -1)
                            {
                                a_FirstBreakTime = Convert.ToInt32(row["시각"]);
                                a_FirstState = recentState;
                            }
                        }
                    }
                }

                oldState = curState;
            }
            return 1;
        }


        public int FindBreakTime(DataTable a_Table, int a_EndIndex, int a_StartTime, ref EasyTrader.Option.CompVal a_ComVal)
        {
            double margin = GlobalVar.CalcOptMargin(a_ComVal.Val);
            double highLimit = a_ComVal.Val + margin;
            double lowLimit = a_ComVal.Val - margin;

            double a_Open = 0.0, a_High = 0.0, a_Low = 0.0, a_Close = 0.0;
            bool result = GetOHLC(m_Table, 0, a_EndIndex, ref a_Open, ref a_High, ref a_Low, ref a_Close);

            int firstBreakTime = -1;
            int firstBreakDownTime = -1;
            int firstBreakUpTime = -1;

            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int recentState = GlobalVar.BreakNone;

            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.NoneRange;
            int openState = GlobalVar.NoneRange;
            int lastUpDown = GlobalVar.NoneRange;

            if (open > highLimit)
            {
                curState = GlobalVar.UpRange;
                lastUpDown = curState;
            }
            else if (open < lowLimit)
            {
                curState = GlobalVar.DownRange;
                lastUpDown = curState;
            }
            else
                curState = GlobalVar.InRange;

            openState = curState;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                double close = Convert.ToDouble(row["종가"]);
                int curTime = Convert.ToInt32(row["시각"]);

                if (low > highLimit)
                    curState = GlobalVar.UpRange;
                else if (high < lowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            if (close < a_ComVal.Val)
                            {
                                recentState = GlobalVar.BreakDown;
                                if (firstBreakDownTime == -1 && curTime >= a_StartTime)
                                {
                                    a_ComVal.FirstBreakDownState = GlobalVar.BreakDown;
                                    a_ComVal.FirstBreakDownTime = curTime;
                                    firstBreakDownTime = curTime;
                                }
                            }
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            if (firstBreakDownTime == -1 && curTime >= a_StartTime)
                            {
                                a_ComVal.FirstBreakDownState = GlobalVar.BreakDown;
                                a_ComVal.FirstBreakDownTime = curTime;
                                firstBreakDownTime = curTime;
                            }
                            lastUpDown = curState;
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            if (close > a_ComVal.Val)
                            {
                                recentState = GlobalVar.BreakUp;
                                if (firstBreakUpTime == -1 && curTime >= a_StartTime)
                                {
                                    a_ComVal.FirstBreakUpState = GlobalVar.BreakUp;
                                    a_ComVal.FirstBreakUpTime = curTime;
                                    firstBreakUpTime = curTime;
                                }
                            }
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            if (firstBreakUpTime == -1 && curTime >= a_StartTime)
                            {
                                a_ComVal.FirstBreakUpState = GlobalVar.BreakUp;
                                a_ComVal.FirstBreakUpTime = curTime;
                                firstBreakUpTime = curTime;
                            }
                            lastUpDown = curState;
                        }
                    }
                    else if (oldState == GlobalVar.InRange)
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            if (a_Low <= a_ComVal.Val)
                            {
                                recentState = GlobalVar.BreakUp;
                                if (firstBreakUpTime == -1 && curTime >= a_StartTime)
                                {
                                    a_ComVal.FirstBreakUpState = GlobalVar.BreakUp;
                                    a_ComVal.FirstBreakUpTime = curTime;
                                    firstBreakUpTime = curTime;
                                }
                            }
                            lastUpDown = curState;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            if (a_High >= a_ComVal.Val)
                            {
                                recentState = GlobalVar.BreakDown;
                                if (firstBreakDownTime == -1 && curTime >= a_StartTime)
                                {
                                    a_ComVal.FirstBreakDownState = GlobalVar.BreakDown;
                                    a_ComVal.FirstBreakDownTime = curTime;
                                    firstBreakDownTime = curTime;
                                }
                            }
                            lastUpDown = curState;
                        }
                    }

                    if (firstBreakTime == -1)
                    {
                        a_ComVal.FirstBreakTime = curTime;
                        a_ComVal.FirstState = recentState;
                        firstBreakTime = curTime;
                    }
                    a_ComVal.RecentBreakTime = curTime;
                    a_ComVal.RecentState = recentState;
                }
                else // 상태가 같을 경우 - 이때는 종가로만 판단을 한다. 종가가 상한선을 넘으면 돌파, 종가가 하한선을 넘으면 붕괴
                {
                    if (oldState == GlobalVar.InRange && curState == GlobalVar.InRange)
                    {
                        if (openState != GlobalVar.InRange)
                        {
                            if (lastUpDown == GlobalVar.UpRange)
                            {
                                if (a_Low <= a_ComVal.Val)
                                {
                                    if (close > a_ComVal.Val)
                                    {
                                        recentState = GlobalVar.BreakUp;
                                        if (firstBreakUpTime == -1 && curTime >= a_StartTime)
                                        {
                                            a_ComVal.FirstBreakUpState = GlobalVar.BreakUp;
                                            a_ComVal.FirstBreakUpTime = curTime;
                                            firstBreakUpTime = curTime;
                                        }

                                        if (firstBreakTime == -1)
                                        {
                                            a_ComVal.FirstBreakTime = curTime;
                                            a_ComVal.FirstState = recentState;
                                            firstBreakTime = curTime;
                                        }
                                        a_ComVal.RecentBreakTime = curTime;
                                        a_ComVal.RecentState = recentState;
                                    }
                                }
                            }
                            else if (lastUpDown == GlobalVar.DownRange)
                            {
                                if (a_High >= a_ComVal.Val)
                                {
                                    if (close < a_ComVal.Val)
                                    {
                                        recentState = GlobalVar.BreakDown;
                                        if (firstBreakDownTime == -1 && curTime >= a_StartTime)
                                        {
                                            a_ComVal.FirstBreakDownState = GlobalVar.BreakDown;
                                            a_ComVal.FirstBreakDownTime = curTime;
                                            firstBreakDownTime = curTime;
                                        }
                                        if (firstBreakTime == -1)
                                        {
                                            a_ComVal.FirstBreakTime = curTime;
                                            a_ComVal.FirstState = recentState;
                                            firstBreakTime = curTime;
                                        }
                                        a_ComVal.RecentBreakTime = curTime;
                                        a_ComVal.RecentState = recentState;
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (close < a_ComVal.Val)
                            {
                                recentState = GlobalVar.BreakDown;
                                if (firstBreakDownTime == -1 && curTime >= a_StartTime)
                                {
                                    a_ComVal.FirstBreakDownState = GlobalVar.BreakDown;
                                    a_ComVal.FirstBreakDownTime = curTime;
                                    firstBreakDownTime = curTime;
                                }
                                if (firstBreakTime == -1)
                                {
                                    a_ComVal.FirstBreakTime = curTime;
                                    a_ComVal.FirstState = recentState;
                                    firstBreakTime = curTime;
                                }
                                a_ComVal.RecentBreakTime = curTime;
                                a_ComVal.RecentState = recentState;
                            }
                            else if (close > a_ComVal.Val)
                            {
                                recentState = GlobalVar.BreakUp;
                                if (firstBreakUpTime == -1 && curTime >= a_StartTime)
                                {
                                    a_ComVal.FirstBreakUpState = GlobalVar.BreakUp;
                                    a_ComVal.FirstBreakUpTime = curTime;
                                    firstBreakUpTime = curTime;
                                }

                                if (firstBreakTime == -1)
                                {
                                    a_ComVal.FirstBreakTime = curTime;
                                    a_ComVal.FirstState = recentState;
                                    firstBreakTime = curTime;
                                }
                                a_ComVal.RecentBreakTime = curTime;
                                a_ComVal.RecentState = recentState;
                            }
                        }
                    }
                }

                oldState = curState;
            }

            return 1;
        }

        private int FindFirstBreakDownTime(DataTable a_Table, int a_EndIndex, double a_HighLimit, double a_LowLimit)
        {
            int firstBreakTime = -1;
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int recentState = GlobalVar.BreakNone;

            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.NoneRange;

            if (open > a_HighLimit)
                curState = GlobalVar.UpRange;
            else if (open < a_LowLimit)
                curState = GlobalVar.DownRange;
            else
                curState = GlobalVar.InRange;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                double close = Convert.ToDouble(row["종가"]);

                if (low > a_HighLimit)
                    curState = GlobalVar.UpRange;
                else if (high < a_LowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                    }
                    else if (oldState == GlobalVar.InRange)
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                    }
                    int k = 0;
                    k = k + 1;
                }
                else // 상태가 같을 경우 - 이때는 종가로만 판단을 한다. 종가가 상한선을 넘으면 돌파, 종가가 하한선을 넘으면 붕괴
                {
                    if (oldState == GlobalVar.InRange && curState == GlobalVar.InRange)
                    {
                        if (close < a_LowLimit)
                        {
                            recentState = GlobalVar.BreakDown;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                        else if (close > a_HighLimit)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                    }
                }

                oldState = curState;
            }
            return firstBreakTime;
        }

        private int FindFirstBreakUpTime(DataTable a_Table, int a_EndIndex, double a_HighLimit, double a_LowLimit)
        {
            int firstBreakTime = -1;
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int recentState = GlobalVar.BreakNone;

            DataRow row = a_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.NoneRange;

            if (open > a_HighLimit)
                curState = GlobalVar.UpRange;
            else if (open < a_LowLimit)
                curState = GlobalVar.DownRange;
            else
                curState = GlobalVar.InRange;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                double close = Convert.ToDouble(row["종가"]);

                if (low > a_HighLimit)
                    curState = GlobalVar.UpRange;
                else if (high < a_LowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                    }
                    else if (oldState == GlobalVar.InRange)
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }
                    int k = 0;
                    k = k + 1;
                }
                else // 상태가 같을 경우 - 이때는 종가로만 판단을 한다. 종가가 상한선을 넘으면 돌파, 종가가 하한선을 넘으면 붕괴
                {
                    if (oldState == GlobalVar.InRange && curState == GlobalVar.InRange)
                    {
                        if (close < a_LowLimit)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                        else if (close > a_HighLimit)
                        {
                            recentState = GlobalVar.BreakUp;
                            firstBreakTime = Convert.ToInt32(row["시각"]);
                            break;
                        }
                    }
                }

                oldState = curState;
            }
            return firstBreakTime;
        }

        // 이 함수는 주어진 시작시간 이후에 발생한 첫 붕괴나 돌파를 수집한다. 
        public int FindFirstBreakUpTime(List<CompVal> a_ValList,  int a_StartTime, int a_EndIndex, ref CompVal a_CurComVal)
        {
            int firstBreakTime = -1;
            if (m_Table == null)
                return -1;
            if (m_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(m_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            double margin = GlobalVar.CalcOptMargin(a_CurComVal.Val);
            double highLimit = a_CurComVal.Val + margin;
            double lowLimit = a_CurComVal.Val - margin;

            int recentState = GlobalVar.BreakNone;

            DataRow row = m_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.NoneRange;

            if (open > highLimit)
                curState = GlobalVar.UpRange;
            else if (open < lowLimit)
                curState = GlobalVar.DownRange;
            else
                curState = GlobalVar.InRange;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = m_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                double close = Convert.ToDouble(row["종가"]);

                int curTime = Convert.ToInt32(row["시각"]);

                if (low > highLimit)
                    curState = GlobalVar.UpRange;
                else if (high < lowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakUpTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                firstBreakTime = curTime;
                                break;
                            }
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakUpTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                firstBreakTime = curTime;
                                break;
                            }
                        }
                    }
                    else if (oldState == GlobalVar.InRange)
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakUpTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                firstBreakTime = curTime;
                                break;
                            }
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                    }
                    int k = 0;
                    k = k + 1;
                }
                else // 상태가 같을 경우 - 이때는 종가로만 판단을 한다. 종가가 상한선을 넘으면 돌파, 종가가 하한선을 넘으면 붕괴
                {
                    if (oldState == GlobalVar.InRange && curState == GlobalVar.InRange)
                    {
                        if (close < lowLimit)
                        {
                            recentState = GlobalVar.BreakDown;
                        }
                        else if (close > highLimit)
                        {
                            recentState = GlobalVar.BreakUp;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakUpTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                firstBreakTime = curTime;
                                break;
                            }
                        }
                    }
                }

                oldState = curState;
            }
            return firstBreakTime;
        }


        // 이 함수는 주어진 시작시간 이후에 발생한 첫 붕괴나 돌파를 수집한다. 
        public int FindFirstBreakDownTime(List<CompVal> a_ValList, int a_StartTime, int a_EndIndex, ref CompVal a_CurComVal)
        {
            int firstBreakTime = -1;
            if (m_Table == null)
                return -1;
            if (m_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(m_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            double margin = GlobalVar.CalcOptMargin(a_CurComVal.Val);
            double highLimit = a_CurComVal.Val + margin;
            double lowLimit = a_CurComVal.Val - margin;

            int recentState = GlobalVar.BreakNone;

            DataRow row = m_Table.Rows[0];
            double open = Convert.ToDouble(row["시가"]);
            int curState = GlobalVar.NoneRange;

            if (open > highLimit)
                curState = GlobalVar.UpRange;
            else if (open < lowLimit)
                curState = GlobalVar.DownRange;
            else
                curState = GlobalVar.InRange;

            int oldState = curState;

            for (int i = 0; i <= endIndex; i++)
            {
                row = m_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                double close = Convert.ToDouble(row["종가"]);

                int curTime = Convert.ToInt32(row["시각"]);

                if (low > highLimit)
                    curState = GlobalVar.UpRange;
                else if (high < lowLimit)
                    curState = GlobalVar.DownRange;
                else
                    curState = GlobalVar.InRange;

                if (oldState != curState)
                {
                    if (oldState == GlobalVar.UpRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakDownTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                break;
                            }
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakDownTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                break;
                            }
                        }
                    }
                    else if (oldState == GlobalVar.DownRange)
                    {
                        if (curState == GlobalVar.InRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                    }
                    else if (oldState == GlobalVar.InRange)
                    {
                        if (curState == GlobalVar.UpRange)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                        else if (curState == GlobalVar.DownRange)
                        {
                            recentState = GlobalVar.BreakDown;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakDownTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                break;
                            }
                        }
                    }
                    int k = 0;
                    k = k + 1;
                }
                else // 상태가 같을 경우 - 이때는 종가로만 판단을 한다. 종가가 상한선을 넘으면 돌파, 종가가 하한선을 넘으면 붕괴
                {
                    if (oldState == GlobalVar.InRange && curState == GlobalVar.InRange)
                    {
                        if (close < lowLimit)
                        {
                            recentState = GlobalVar.BreakDown;
                            if (curTime >= a_StartTime)
                            {
                                a_CurComVal.FirstBreakDownTime = curTime;
                                a_ValList.Add(a_CurComVal);
                                break;
                            }
                        }
                        else if (close > highLimit)
                        {
                            recentState = GlobalVar.BreakUp;
                        }
                    }
                }

                oldState = curState;
            }
            return firstBreakTime;
        }

        private int FindRecentBreakTime(DataTable a_Table, int a_EndIndex, double a_CompVal, out double a_Min, out double a_Max)
        {
            a_Min = 999.0;
            a_Max = -999.0;
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);

            a_Min = low;
            a_Max = high;


            int curPos = 0;
            if (a_CompVal < low)
                curPos = 1;
            else if (a_CompVal > high)
                curPos = -1;
            else
            {
                curPos = 0;
                breakUpTime = Convert.ToInt32(row["시각"]);
                return breakUpTime;
            }
            int oldPos = curPos;
            for (int i = endIndex; i >= 0; i--)
            {
                row = a_Table.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);

                if (high > a_Max)
                    a_Max = high;
                if (low < a_Min)
                    a_Min = low;

                if (high >= a_CompVal && low <= a_CompVal)
                {
                    breakUpTime = Convert.ToInt32(row["시각"]);
                    break;
                }
            }
            return breakUpTime;
        }

        private int FindRecentBreakIndex(DataTable a_Table, int a_EndIndex, double a_CompVal, out double a_Min, out double a_Max)
        {
            a_Min = 999.0;
            a_Max = -999.0;
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakIndex = -1;
            DataRow row = a_Table.Rows[endIndex];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);
            a_Min = low;
            a_Max = high;
            int curPos = 0;
            if (a_CompVal < low)
                curPos = 1;
            else if (a_CompVal > high)
                curPos = -1;
            else
            {
                curPos = 0;
                breakIndex = endIndex;
                return breakIndex;
            }
            int oldPos = curPos;
            for (int i = endIndex; i >= 0; i--)
            {
                row = a_Table.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);

                if (high >= a_CompVal && low <= a_CompVal)
                {
                    if (high > a_Max)
                        a_Max = high;
                    if (low < a_Min)
                        a_Min = low;
                    breakIndex = i;
                    break;
                }
            }
            return breakIndex;
        }


        private int FindFirstBreakTime(DataTable a_Table, int a_EndIndex, double a_CompVal)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[0];
            double high = Convert.ToDouble(row["고가"]);
            double low = Convert.ToDouble(row["저가"]);

            if (a_CompVal <= high && a_CompVal >= low)
            {
                breakUpTime = Convert.ToInt32(row["시각"]);
                return breakUpTime;
            }

            for (int i = 0; i < endIndex; i++)
            {
                row = a_Table.Rows[i];
                high = Convert.ToDouble(row["고가"]);
                low = Convert.ToDouble(row["저가"]);
                if (low <= a_CompVal && high >= a_CompVal)
                {
                    breakUpTime = Convert.ToInt32(row["시각"]);
                    break;
                }
            }

            return breakUpTime;
        }

        private int FindFirstBreakTime(DataTable a_Table, int a_EndIndex, double a_HighLimit, double a_LowLimit)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            
            for (int i = 0; i <= endIndex; i++)
            {
                DataRow row = a_Table.Rows[i];
                double high = Convert.ToDouble(row["고가"]);
                double low = Convert.ToDouble(row["저가"]);
                if ((a_LowLimit >= low && a_LowLimit <= high) || 
                    (a_HighLimit >= low && a_HighLimit <= high))
                {
                    breakUpTime = Convert.ToInt32(row["시각"]);
                    break;
                }
            }

            return breakUpTime;
        }

        // 현재 인덱스에서 주어진 값과 처음 만나는 지점까지의 고점과 저점을 찾는다.
        // 
        private int FindMinMaxBeforeCross(DataTable a_Table, int a_EndIndex, double a_CompVal, out double a_Min, out double a_Max)
        {
            a_Min = 999.0;
            a_Max = -999.0;
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;

            int endIndex = FindCurIndex(a_Table, a_EndIndex);
            if (endIndex < 0)
                return -1;

            int breakUpTime = -1;
            DataRow row = a_Table.Rows[endIndex];
            double close = Convert.ToDouble(row["종가"]);
            // 종가가 비교값보다 위에 있으므로 여기서 고가를 수집한다.
            if (close > a_CompVal)
            {
                for (int i = endIndex; i >= 0; i--)
                {
                    row = a_Table.Rows[i];
                    double open = Convert.ToDouble(row["시가"]);
                    double low = Convert.ToDouble(row["저가"]);
                    double high = Convert.ToDouble(row["고가"]);
                    close = Convert.ToDouble(row["종가"]);
                    if (open <= a_CompVal || low <= a_CompVal)
                    {
                        breakUpTime = Convert.ToInt32(row["시각"]);
                        if (open > a_Max)
                            a_Max = open;
                        if (open < a_Min)
                            a_Min = open;

                        if (low > a_Max)
                            a_Max = low;
                        if (low < a_Min)
                            a_Min = low;

                        if (high > a_Max)
                            a_Max = high;
                        if (high < a_Min)
                            a_Min = high;
                        break;
                    }
                }
            }
            else if (close < a_CompVal)
            {
                for (int i = endIndex; i >= 0; i--)
                {
                    row = a_Table.Rows[i];
                    double open = Convert.ToDouble(row["시가"]);
                    double high = Convert.ToDouble(row["고가"]);
                    double low = Convert.ToDouble(row["저가"]);
                    if (open >= a_CompVal || high >= a_CompVal)
                    {
                        breakUpTime = Convert.ToInt32(row["시각"]);
                        if (open > a_Max)
                            a_Max = open;
                        if (open < a_Min)
                            a_Min = open;

                        if (low > a_Max)
                            a_Max = low;
                        if (low < a_Min)
                            a_Min = low;

                        if (high > a_Max)
                            a_Max = high;
                        if (high < a_Min)
                            a_Min = high;
                        break;
                    }
                }
            }
            return breakUpTime;
        }

        // 정확한 인덱스를 찾는다. 정확한 인덱스를 찾지 못하면 신호를 내지 않는 것으로 한다.
        public int FindExactIndex(DataTable a_Table, int a_CurIndex)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;
            if (a_CurIndex < 0)
                return -1;

            int index = -1;
            for (int i = a_Table.Rows.Count - 1; i >= 0; i--)
            {
                DataRow row = a_Table.Rows[i];
                string curTime = row["시각"].ToString();
                int sysTime = GlobalVar.DayIndexToTime(a_CurIndex);
                if (Convert.ToInt32(curTime) == sysTime)
                {
                    index = i;
                    //Console.WriteLine("index" + index.ToString());
                    break;
                }
            }

            return index;
        }

        
        public int FindCurIndex(DataTable a_Table, int a_CurIndex)
        {
            if (a_Table == null)
                return -1;
            if (a_Table.Rows.Count == 0)
                return -1;
            if (a_CurIndex < 0)
                return -1;

            int index = 0;
            for (int i = a_Table.Rows.Count - 1; i >= 0; i--)
            {
                DataRow row = a_Table.Rows[i];
                string curTime = row["시각"].ToString();
                int curIndex = GlobalVar.DayIndex(curTime);
                if (curIndex <= a_CurIndex)
                {
                    index = i;
                    //Console.WriteLine("index" + index.ToString());
                    break;
                }
            }

            return Math.Min(index, a_Table.Rows.Count - 1);
        }
    }
}
